'Reactjs setState asynchronous

I am building a little search engine and got following problem:

Everytime I enter a query, the last letter is missing. I figured out, that it has something to do with setState and that it is not asynchronous... But I can not come up with a solution fo my case.

Her is my function:

  searchHandler = ({ target: { value } }) => {

  this.setState({ term: value });
    this.updateMessage(value);

    if(this.state.message.length === 0){
      this.setState({hasMoreItems: false})

      this.componentDidMount();
    }else{

  var requestUrl = 'https://questdb.herokuapp.com/all?q='
  fetch(requestUrl + this.state.message).then((response)=>{
      return response.json();
  }) .then((data)=>{
      this.setState({ tracks: data});

  })
}
}


updateMessage = message => this.setState({ message });

Do you have any suggestions for me?

Thanks a lot!



Solution 1:[1]

In general, you want to use the second argument of setState(), which accepts a callback function which will run with the updated state. Here's an example:

import React, { Component } from 'react';
import { render } from 'react-dom';

class App extends React.Component { 
  state = {
    value: '',
  }

  handleChange = (e) => {
    e.preventDefault();
    const { value } = e.target;
    this.setState({ value }, () => {
      console.log('Value is:', this.state.value );
    })
  }

  render() { 
    return (
      <input value={this.state.value} onChange={this.handleChange} />
    )
  }
}

render(<App />, document.getElementById('root'));

Live example here.

Solution 2:[2]

this.setState() can be passed a callback function that will execute once the state is actually set with the new value. You can use it like so:

this.setState({something: newValue}, () => {
    console.log(this.state.something) // this will print out the new value
});

Solution 3:[3]

It's a bit late, but I came up with a solution for this a while back and I've been using it in pretty much every project I work on that needs it. It does not do the batching, and it will instead WAIT until the state update finishes before returning. Which... is sometimes exactly what you want. Anyways, it's convenient and easy to use.

setStateAsync code:

/**
 * Allows you to await setState calls rather than use the callback function
 * Declaration: private setStateAsync = setStateAsyncFactory(this);
 * Usage: await this.setStateAsync({myProp: val});
 * @param component
 */
export const setStateAsyncFactory = <P, S>(
    component: React.Component<P, S>
) => {
    return <K extends keyof S>(state:
        ((prevState: Readonly<S>, props: Readonly<P>) => (Pick<S, K> | S | null)) |
        Pick<S, K> | S | null) => {
        return new Promise(resolve => component.setState(state, () => resolve(undefined)));
    };
};

/**
 * Allows you to await setState calls rather than use the callback function
 * Usage: await this.setStateAsync(component, {myProp: val});
 * @param component
 * 
 */
export const setStateAsyncDirect = <P, S, K extends keyof S>(
    component: React.Component<P, S>,
    state:
        ((prevState: Readonly<S>, props: Readonly<P>) => (Pick<S, K> | S | null)) |
        Pick<S, K> | S | null
) => new Promise(resolve => component.setState(state, () => resolve(undefined)));

Usage:

export class FooEntry extends React.PureComponent<FooEntryProps, FooEntryState>  {
    private setStateAsync = setStateAsyncFactory(this);
    ...

private someAsyncFunc = async () => {
    await this.setStateAsync({ foo: 3});
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Colin Ricardo
Solution 2 Bojan Ivanac
Solution 3 Pangamma