javascript - Prevent this.state to be used with setState - Stack Overflow

The reference states:setState() does not always immediately update the ponent. It may batch or defer th

The reference states:

setState() does not always immediately update the ponent. It may batch or defer the update until later. This makes reading this.state right after calling setState() a potential pitfall. Instead, use ponentDidUpdate or a setState callback (setState(updater, callback)), either of which are guaranteed to fire after the update has been applied. If you need to set the state based on the previous state, read about the updater argument below.

So it is considered a mistake in React to use this.state values together with setState because setState is asynchronous and may result in updating the state with wrong values (a demo):

// destructured
const { state, setState } = this;
setState({ foo: state.foo });

// destructured
const { foo } = this.state;
setState({ foo });

// undestructured
this.setState({ foo: this.state.foo });

While this would be proper way to update the state (a demo):

// destructured
this.setState(({ foo }) => ({ foo }));

// undestructured
this.setState(state => ({ foo: state.foo }));

Is there ESLint rule or other way to prevent some or all of these cases where this.state can be misused?

I assume it may be hard but possible to solve this case with static analysis.

The reference states:

setState() does not always immediately update the ponent. It may batch or defer the update until later. This makes reading this.state right after calling setState() a potential pitfall. Instead, use ponentDidUpdate or a setState callback (setState(updater, callback)), either of which are guaranteed to fire after the update has been applied. If you need to set the state based on the previous state, read about the updater argument below.

So it is considered a mistake in React to use this.state values together with setState because setState is asynchronous and may result in updating the state with wrong values (a demo):

// destructured
const { state, setState } = this;
setState({ foo: state.foo });

// destructured
const { foo } = this.state;
setState({ foo });

// undestructured
this.setState({ foo: this.state.foo });

While this would be proper way to update the state (a demo):

// destructured
this.setState(({ foo }) => ({ foo }));

// undestructured
this.setState(state => ({ foo: state.foo }));

Is there ESLint rule or other way to prevent some or all of these cases where this.state can be misused?

I assume it may be hard but possible to solve this case with static analysis.

Share Improve this question edited Oct 8, 2018 at 10:58 Estus Flask asked Oct 8, 2018 at 9:17 Estus FlaskEstus Flask 224k79 gold badges472 silver badges611 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 3

eslint-plugin-react will do this check with react/no-access-state-in-setstate rule

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.

If you use:

// destructured
const { state, setState } = this;
setState({ foo: state.foo });

Eslint still warns you because of state.foo (accessing property of an object). To avoid this, you can define like:

// destructured
const { state: { foo }, setState } = this;
setState({ foo });

But if you use:

// undestructured
this.setState({ foo: this.state.foo });

Then, ESLINT will warn you to use destructuring syntax like:

const { foo } = this.state
this.setState({foo})

Note: since foo is the variable name to update and the name matches, we can use just {foo} and is same as {foo: foo}.


Also, and however, I prefer to use this.setState() syntax rather than destructuring to this. Because, in any application, we use this whenever necessary. And using const { ... } = this seems to be confusing if we look between the code when we see setState rather than this.setState. Thinking as of third developer.


From the ments, you wanted to update the state one after another, then you should be using callback like:

onClick = () => {
   this.setState({ foo: 'Bar' }, () => {
      this.setState({ foo: this.state.foo + '!' });
   });
}

Now, you'll be able to see the changes to Hello Bar! in your demo.

If you use setState like this:

onClick = () => {
   this.setState({ foo: 'Bar' })
   this.setState({ foo: this.state.foo + '!' });
   // obviously, better to use updater syntax though.
}

Then the first setState will be overridden by the last one. And you'll get the changes to Hello Foo! in your demo.

Also, the documentation states the same. The updater syntax is just a handy method but results the same exactly as without the updater syntax. The most important role is only with its callback syntax. The callback syntax is used so that you can access the updated state right after its updates.


To know more about destructuring syntax. You may follow my another post where, you can find detailed information and some links that will be a lot to be familiar.

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744291688a4567062.html

相关推荐

  • javascript - Prevent this.state to be used with setState - Stack Overflow

    The reference states:setState() does not always immediately update the ponent. It may batch or defer th

    7天前
    20

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信