Search code examples
javascriptlistviewreactjsreact-nativetextinput

onChange triggers only after 2 text inputs


I have a weird behaviour from my "TextInput". I am trying to filter a ListView based on a TextInput entry:

export default class SearchTabScreen1 extends Component {
  constructor(props) {
    super(props);
    this.state = {
      searchText:'',
      data:[]
    };
}

setSearchText(event) {
    var reset = realm.objects('User');
    if (this.state.data !== reset){
    this.setState({
      data:realm.objects('User')
    });

    const searchText = event.nativeEvent.text;
    this.setState({searchText:searchText});
    console.log(this.state.searchText);

    var searchString = this.state.searchText;
    if(searchString != ""){
      let searchResult = realm.objects('User').filtered('name BEGINSWITH[c] $0', searchString);
      var filteredData = searchResult;

      this.setState({
        data : filteredData
      });
      console.log("FILTERED", filteredData);
    }
  }
}

render() {
      return (
        <View style={{flex: 1, padding: 20}}>
          <TextInput
            ref="recherche"
            placeholder="Search"
            autoCorrect={true}
            returnKeyLabel="search"
            underlineColorAndroid="black"
            value = {this.state.searchText}
            onChange={this.setSearchText.bind(this)}
          />
          <ListViewDico
            navigator={this.props.navigator}
            dataFromParent={this.state.data}
          />
        </View>

The problem is when I type an 'L', for example, in the TextInput the log: console.log(this.state.searchText); shows nothing.

The log shows this 'L' only after I typed a second character (whatever it is) and so on.

I always get a response at a "t+1 entry".

I would appreciate some help, thanks.


Solution

  • The reason that it happens is that setState doesn't immediately mutate the state, but takes time and as Javascript is async your console.log() gets executed before the state is mutated and hence you don't get the updated value, only when it is executed the next time you see the old value. The solution is to call the console.log() in the setState callback.

     this.setState({searchText:searchText}, () => {
         console.log(this.state.searchText);
     });
    

    Code:

    setSearchText(event) {
        var reset = realm.objects('User');
        if (this.state.data !== reset){
        this.setState({
          data:realm.objects('User')
        });
    
        const searchText = event.nativeEvent.text;
        this.setState({searchText:searchText}, function() {
             console.log(this.state.searchText);
        });
    
    
        var searchString = searchText;
        if(searchString != ""){
          let searchResult = realm.objects('User').filtered('name BEGINSWITH[c] $0', searchString);
          var filteredData = searchResult;
    
          this.setState({
            data : filteredData
          }, function() {
              console.log("FILTERED", filteredData);
          });
    
        }
      }
    }