props和state之间的确切区别是什么?理解它们的工作原理相当容易,尤其是在上下文中查看时,但是从概念上理解它们也有些困难。一开始令人困惑,因为它们都具有抽象术语,并且它们的值看起来相同,但是它们也具有不同的作用。本文章同步发布在我的博客:👉xueshiming.cn
setState 实际做了什么?
setState()
会对一个组件的 state 对象安排一次更新。当 state
改变了,该组件就会重新渲染。
state 和 props 之间的区别是什么?
props(“properties” 的缩写)
和 state
都是普通的 JavaScript
对象。它们都是用来保存信息的,这些信息可以控制组件的渲染输出,而它们的几个重要的不同点就是:
-
props
是传递给组件的(类似于函数的形参),而state
是在组件内被组件自己管理的(类似于在一个函数内声明的变量)。 -
props
是不可修改的,所有React
组件都必须像纯函数一样保护它们的props
不被更改。 由于props
是传入的,并且它们不能更改,因此我们可以将任何仅使用props
的React
组件视为pureComponent
,也就是说,在相同的输入下,它将始终呈现相同的输出。 -
state
是在组件中创建的,一般在constructor
中初始化state
-
state
是多变的、可以修改,每次setState
都异步更新的。
为什么 setState 给了我一个错误的值?
在 React
中,this.props
和 this.state
都代表着已经被渲染了的值,即当前屏幕上显示的值。
调用 setState
其实是异步的 —— 不要指望在调用 setState
之后,this.state
会立即映射为新的值。如果你需要基于当前的 state
来计算出新的值,那你应该传递一个函数,而不是一个对象(详情见下文)。
代码不会像预期那样运行的示例:
incrementCount() {
// 注意:这样 *不会* 像预期的那样工作。
this.setState({count: this.state.count + 1});
}
handleSomething() {
// 假设 `this.state.count` 从 0 开始。
this.incrementCount();
this.incrementCount();
this.incrementCount();
// 当 React 重新渲染该组件时,`this.state.count` 会变为 1,而不是你期望的 3。
// 这是因为上面的 `incrementCount()` 函数是从 `this.state.count` 中读取数据的,
// 但是 React 不会更新 `this.state.count`,直到该组件被重新渲染。
// 所以最终 `incrementCount()` 每次读取 `this.state.count` 的值都是 0,并将它设为 1。
// 问题的修复参见下面的说明。
}
那么应该如何更新那些依赖于当前的
state
的state
呢?
给 setState
传递一个函数,而不是一个对象,就可以确保每次的调用都是使用最新版的 state
。
给 setState 传递一个对象与传递一个函数的区别是什么?
传递一个函数可以让你在函数内访问到当前的 state
的值。因为 setState
的调用是分批的,所以你可以链式地进行更新,并确保它们是一个建立在另一个之上的,这样才不会发生冲突:
incrementCount() {
this.setState((state) => {
// 重要:在更新的时候读取 `state`,而不是 `this.state`。
return {count: state.count + 1}
});
}
handleSomething() {
// 假设 `this.state.count` 从 0 开始。
this.incrementCount();
this.incrementCount();
this.incrementCount();
// 如果你现在在这里读取 `this.state.count`,它还是会为 0。
// 但是,当 React 重新渲染该组件时,它会变为 3。
}
setState 什么时候是异步的?
目前,在事件处理函数内部的 setState
是异步的。(V16.10)
例如,如果 Parent
和 Child
在同一个 click
事件中都调用了 setState
,这样就可以确保 Child
不会被重新渲染两次。取而代之的是,React
会将该 state
等到浏览器事件结束的时候,再统一地进行更新。这种机制可以在大型应用中得到很好的性能提升。