Wonka Wonka - 5 months ago 129
Javascript Question

mobX - Filter countries in react native?

I have an array of 3 countries and a text input to filter them. If you type in the text input, it should check for what you typed against the country name, which should return the new filtered list of countries that match the filtered text. It should also display the inputted text next to

Typed Text:


import React, { Component } from 'react'
import { View, Text, TextInput } from 'react-native'
import { observable, action } from 'mobx';
import { observer } from 'mobx-react/native'

@observer
export default class Country extends Component {
@observable filterTermValue;
@observable countriesList = [
{'slug': 'amsterdam', 'name': 'Amsterdam'},
{'slug': 'usa', 'name': 'United States'},
{'slug': 'vienna', 'name': 'Vienna'}
];

render() {
return (
<View>
<Text>Typed Text: {this.filterTermValue}</Text>
<TextInput placeholder="Start typing country"
value={this.filterTermValue}
onChange={this.onChangeFilterTerm} />

{this.countriesList.map(country =>
<View key={country.slug}>
<Text>{country.name}</Text>
</View>
)}
</View>
)
}

@action onChangeFilterTerm = (e) => {
this.filterTermValue = e.target.value;

this.countriesList.replace(this.countriesList.filter(el => el.name.toLowerCase().indexOf(this.filterTermValue.toLowerCase()) > -1));
}
}


That's all the logic I have and I can't get it to work. The only thing that works is the country list loads the original array. Once I start typing in the input, the value is undefined and never prints, and the list is never filtered. I also tried
async
actions and
runInAction
I even tried computed to return the filtered list, but can't seem to get it to work.

What is the right way to do this in mobX?

Answer

I saw a few possible problems, so I slightly changed the approach.

Working example

UPDATED Working example. Note this is untested in react-native, but it should work.

The code

@observer
class Country extends React.Component {


    @observable filterTermValue = '';
    @observable countriesList = [
      {'slug': 'amsterdam', 'name': 'Amsterdam'},
      {'slug': 'usa', 'name': 'United States'},
      {'slug': 'vienna', 'name': 'Vienna'}
    ];

    @computed get filtered() {
      let filteredList = this.countriesList.filter(
        t=>t.name.toLowerCase().indexOf(this.filterTermValue)>-1
      );
      if (filteredList.length)
        return filteredList;
      return this.countriesList;
    }

    render() {
        return (
          <div>
              Term: <input placeholder="Start typing country"
                 onKeyUp={this.onChangeFilterTerm} />

              {this.filtered.map(country =>
                  <div key={country.slug}>
                    <p>{country.name}</p>
                  </div>
              )}
          </div>
        )
    }

    @action onChangeFilterTerm = value => {
        this.filterTermValue = value.toLowerCase();
    }
}

React-native gotchyas

Use onChangeText correct signature

jsx:

 <TextInput placeholder="Start typing country"
    onChangeText={(text) => this.setState({text})}
  />

js:

    @action onChangeFilterTerm = value => {
        this.filterTermValue = value.toLowerCase();
    }

Use mobx-react/native

If its still not working, I would double check this:

Dont:

import {observer} from 'mobx-react';

Do:

import {observer} from 'mobx-react/native';
Comments