Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ESLint: Use callback in setState when referencing the previous state

For this piece of code I am getting eslint(AirBnb config) error: Use callback in setState when referencing the previous state

Does this error influence performance somehow and how can it be solved?

  handleSelect(event) {
    const entry = event.nativeEvent;

    if (entry == null) {
      this.setState({ ...this.state, selectedEntry: entry });
    } else
      this.setState({
        ...this.state,
        selectedEntry: JSON.stringify(entry),
        markerIsEnabled: true
      });

    console.log(event.nativeEvent);
  }
like image 398
lecham Avatar asked May 07 '19 14:05

lecham


2 Answers

As you can see in documentation

This rule should prevent usage of this.state inside setState calls. Such usage of this.state might result in errors when two state calls are called in batch and thus referencing old state and not the current state. An example can be an increment function:

function increment() {
  this.setState({value: this.state.value + 1});
}

If these two setState operations is grouped together in a batch it will look be something like the following, given that value is 1:

setState({value: 1 + 1})
setState({value: 1 + 1})

This can be avoided with using callbacks which takes the previous state as first argument:

function increment() {
  this.setState(prevState => ({value: prevState.value + 1}));
}

So this is why you have that rule, to avoid erros like this example.

In your case, what you should do is

handleSelect({ nativeEvent }) {    
    if (nativeEvent == null) {
        this.setState(previousState => ({
            ...previousState, 
            selectedEntry: nativeEvent
        }));
    } else {
      this.setState(previousState => ({
        ...previousState,
        selectedEntry: JSON.stringify(entry),
        markerIsEnabled: true
      }));
    }
}

But for your case, this an error won't happen because you don't have two consecutives setState and also, ...this.state or ...prevState won't make any diference because you aren't using the previous state to set a new state.

So for the code you provided in your question, just remove ...this.state and it will work fine, with no errors.

like image 135
Vencovsky Avatar answered Nov 14 '22 12:11

Vencovsky


You can remove ...this.state from setState because it will only update parameters in the state you have changed.

You can see in the React documentation that setState(stateChange) performs a performs a shallow merge of stateChange into the state.

Object.assign(
  previousState,
  stateChange,
  ...
)

This means you don't need to be passing your previous state in, unless new properties depend on it, as setState will do this merge for you.

handleSelect(event) {
    const entry = event.nativeEvent;

    if (entry == null) {
      this.setState({ selectedEntry: entry });
    } else {
      this.setState({
        selectedEntry: JSON.stringify(entry),
        markerIsEnabled: true
      });
    }

    console.log(event.nativeEvent);
  }
like image 6
Cameron Downer Avatar answered Nov 14 '22 12:11

Cameron Downer