ReactJS 中的 this.state 和 this.setstate 有啥区别?

Posted

技术标签:

【中文标题】ReactJS 中的 this.state 和 this.setstate 有啥区别?【英文标题】:What the difference of this.state and this.setstate in ReactJS?ReactJS 中的 this.state 和 this.setstate 有什么区别? 【发布时间】:2016-06-22 09:05:02 【问题描述】:

我想更改hasSubmit 键的值,就像在第一个代码部分中一样。我知道这是不推荐的。但是第二段代码是异步的,我不想用setState的回调函数。

this.statesetState有什么区别? 有什么方法可以立即改变状态值hasSubmit

第一个代码:

this.state.hasSubmit = false
this.setState()
//Code that will use `hasSubmit`.

第二个代码:

this.setState(
   hasSubmit: false,
);
//Code that will use `hasSubmit`.

添加:

场景是这样的:

    hasSubmitgetInitialState() 中设置false。 当我点击submit 按钮时,hasSubmit 将变为false。 提交时hasSubmit 将更改为true

第一次点击submit没问题,hasSubmit会设置成true

但是第二次点击submit使用Second asynchronous code会出错,因为hasSubmit还是true,而First Code可以解决问题。

【问题讨论】:

你想要这个的最终目标是什么?你能详细说明一下吗?我可以将您推荐给文档,但我假设您已经这样做了,所以我想知道您想要实现的目标。 【参考方案1】:

React docs 是这样说的:

永远不要直接改变this.state,因为之后调用 setState() 可能会替换你所做的改变。将 this.state 视为不可变的。

setState() 不会立即改变 this.state 而是创建一个挂起的状态转换。调用此方法后访问this.state 可能会返回现有值。

不保证 setState 调用的同步操作,并且调用可能会被批处理以提高性能。 setState() 将始终触发重新渲染,除非在 shouldComponentUpdate() 中实现了条件渲染逻辑。

如果正在使用可变对象并且无法在shouldComponentUpdate() 中实现逻辑,则仅在新状态与先前状态不同时调用setState() 将避免不必要的重新渲染。

按照设计的方式使用 API 总是明智的。如果文档说不要改变你的状态,那么你最好不要改变你的状态。

虽然setState() 在技术上可能是异步的,但它肯定不会以任何明显的方式变慢。组件的render() 函数将在很短的时间内被调用。

直接设置状态的一个缺点是 React 的生命周期方法 - shouldComponentUpdate()componentWillUpdate()componentDidUpdate() - 依赖于使用 setState() 调用的状态转换。如果直接更改状态并使用空对象调用setState(),则无法再实现这些方法。

另一个是它只是糟糕的编程风格。你在两个语句中做你可以在一个语句中做的事情。

此外,这里没有实际的好处。在这两种情况下,render() 在调用setState()(或forceUpdate())之前都不会被触发。

您声称需要这样做,但没有实际解释该需要是什么。也许您想更详细地说明您的问题。可能有更好的解决方案。

最好使用框架而不是反对它。

更新

来自下面的cmets:

需要的是我想在下面使用更改后的hasSubmit。

好的,我现在明白了。如果您需要立即使用未来状态属性,最好的办法就是将其存储在局部变量中。

const hasSubmit = false;

this.setState(
  hasSubmit: hasSubmit
);

if (hasSubmit)  
  // Code that will use `hasSubmit` ...

【讨论】:

需要的是我想使用下面更改的hasSubmit 我尝试了第一个代码。方法componentWillUpdate()componentDidUpdate()render()也将被调用,hasSubmit的值更改为true 1) 我明白了。我已经更新了我的答案来解决这个问题。 2) 那些生命周期方法不能再有意义地将this.statenextStateprevState 进行比较。 您说维护局部变量的事实并不好 imo。这可以通过 setstate 方法的回调作为文档来实现。 添加一个异步回调函数远比一个简单的局部变量笨重得多。它也没有抓住重点。查询状态是不必要的。你不需要get你刚刚set【参考方案2】:

如果你想改变状态并通过react触发重新渲染: 使用第二个代码。

  this.setState(
    hasSubmit: false,
  );

第一个代码的问题/错误:

  this.state.hasSubmit = false      // Updates state directly: 
                                    // You are not supposed to do this
                                    // except in ES6 constructors
  this.setState()                 // passes an empty state to react.
                                    // Triggers re-render without mutating state

【讨论】:

答案清晰易懂 你说的是this code does not use setState callback:,但在这两个例子中你都使用了setState——这是一个错字吗? setState 可以采用可选的回调参数。在状态更新后可以使用它来做一些事情。这并不是一个错字:我使用了setState,但没有传递任何回调参数。这确实令人困惑,所以我删除了参考;)【参考方案3】:

this.setState 维护了 react 组件的生命周期,并且看起来不像变异变量(即使在内部它确实会改变状态)。因此,反应循环中的单向流程保持不变,没有任何副作用。

需要注意的是,使用 this.setState 不适用于 ES6 类中的构造函数。我们需要在 ES6 构造函数中使用this.state = 模式而不是this.setState

【讨论】:

是的。很好地观察到 this.setState 语法在 ES6 类构造函数中是不允许的。可能是因为在构造函数中您没有修改状态,而是第一次对其进行初始化。 this.setState 不允许在构造函数中使用,因为 setState 可以批处理并且是异步的,因此这可能意味着组件最终可能具有与预期或初始化时不同的状态.出于同样的原因,也不鼓励 AJAX 调用。【参考方案4】:

您永远不应忽视文档建议。在撰写本文时,setState 允许第二个参数是 setState 和重新渲染完成时的回调函数。由于您从未向我们提供您的代码将如何使用 hasSubmit 值,我相信其他一些人可能会在他们想要确保 hasSubmit 已更改时发现这很有用。

【讨论】:

我相信这应该是答案。正如最佳答案所暗示的那样,无需维护另一个局部变量来保存该值。【参考方案5】:

您应该在第一个示例中使用this.forceUpdate() 来强制更新状态。例如:

this.state.hasSubmit = false;
this.forceUpdate();

但最好使用this.setState,因为它是 React 引擎的 init native check-state mecanizm,比强制更新更好。

如果你只是直接更新this.state 的任何参数而没有setState,react render mecanizm 将不会知道状态的某些参数已更新。

【讨论】:

在官方文档here 中:“通常你应该尽量避免使用 forceUpdate() 并且只在 render() 中读取 this.props 和 this.state。”在这种特殊情况下, forceUpdate() 不是一个好的解决方案。 对于真正深度嵌套的状态 JSON 对象,例如深度嵌套的数组,用setState 更新状态是一件很痛苦的事情

以上是关于ReactJS 中的 this.state 和 this.setstate 有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我们需要在 ReactJS 中使用 bind() 来访问 this.props 或 this.state? [复制]

ReactJS 中的内联样式

消失的值this.state.array ReactJS

TypeError:this.state.users.map不是函数reactjs

为啥使用当前状态作为参数时this.state中的()

基本处理形式ReactJs中的未定义输入错误