防止 this.state 与 setState 一起使用

Prevent this.state to be used with setState

The reference 状态:

setState() does not always immediately update the component. It may batch or defer the update until later. This makes reading this.state right after calling setState() a potential pitfall. Instead, use componentDidUpdate 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.

因此在 React 中将 this.state 值与 setState 一起使用被认为是错误的,因为 setState 是异步的并且可能导致使用错误的值更新状态(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 });

虽然这是更新状态的正确方法(demo):

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

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

是否有 ESLint 规则或其他方法来防止 this.state 可能被滥用的部分或所有情况?

我认为用静态分析解决这个问题可能很难,但有可能。

如果您使用:

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

Eslint 仍然会因为 state.foo(访问对象的 属性)而警告您。为避免这种情况,您可以定义如下:

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

但是如果你使用:

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

然后,ESLINT 会警告你使用像这样的解构语法:

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

注意:由于foo是要更新的变量名并且名称匹配,我们可以只使用{foo}并且与{foo: foo}相同。


另外,但是,我更喜欢使用 this.setState() 语法而不是解构为 this。因为,在任何应用程序中,我们都会在必要时使用 this。如果我们在看到 setState 而不是 this.setState 时查看代码,那么使用 const { ... } = this 似乎会造成混淆。以第三方开发人员的身份思考。


根据评论,你想一个接一个地更新状态,那么你应该使用像这样的回调:

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

现在,您将能够在演示中看到对 Hello Bar! 的更改。

如果你像这样使用 setState:

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

那么第一个setState将被最后一个覆盖。您将在演示中看到对 Hello Foo! 的更改。

此外,文档中也有同样的说明。 updater 语法只是一种方便的方法,但结果与没有 updater 语法的结果完全相同。最重要的作用只是它的回调语法。使用回调语法,以便您可以在更新后立即访问更新后的状态。


了解更多关于解构语法的信息。您可以关注 那里,您可以找到详细信息和一些熟悉的链接。

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

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.