做者 : 墨成 javascript
React 版本 :16.4.1html
仔细阅读官网setState的描述会发现里面透露的信息量巨大,我也建议初学者在学习 React以前仔细阅读原始文档,如下是我我的在阅读文档时的一些领悟,配合了一些翻译和讲解,限于我的水平,不足之处,各位请多多指出 java
setState(updater[, callback])复制代码
setState()
enqueues changes to the component state and tells React that this component and its children need to be re-rendered with the updated state. This is the primary method you use to update the user interface in response to event handlers and server responses.react
翻译: setState()
经过队列的形式保存组件状态并告诉React这个组件和他的子组件须要从新渲染。这是咱们经过事件或服务器响应更新用户接口的主要方法(也就是说咱们最经常使用) git
解释:无 github
Think of setState()
as a request rather than an immediate command to update the component. For better perceived performance, React may delay it, and then update several components in a single pass. React does not guarantee that the state changes are applied immediately.性能优化
翻译: setState()
只是做为一个请求而不是一个马上执行的指令去更新组件。为了更好的性能,React会延迟执行,而后经过一种单一(这个单一在这里的意思是归类的意思)的方式去更新几个组件。React不会马上把state
的改变应用到组件上 bash
解释:这句的话的意思很明显就是告诉你 : React的 setState
是"异步"的,React 在没有从新渲染以前对state
的作了一些处理以达到最佳的性能,实例代码:服务器
//Async.js
state = {value:'default value'};
changeValue=()=>{
console.log(`Before change,value is ${this.state.value}`);
this.setState(
{value:'I have a new value'}
)
// 经过setState修改了state中value的值,打印的结果并非最新的值,即修改没有生效
console.log(`After change,value is ${this.state.value}`);
console.log(`Casue setState is asynchronous ,so you will see the same value in this function`);
};复制代码
//the result
Before change,value is default value
After change,value is default value
Casue setState is asynchronous ,so you will see the same value in this function
复制代码
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.app
翻译: setState()
并不老是马上更新组件(言下之意就是有办法能够马上更新,后面会讲道这部份内容)。随后它会使用批处理或延迟更新 。在你调用setState()
后马上读取 this.state
的值不会生效(原文叫 潜在的陷阱)。相反,使用componentDidUpdate 或者 setState 回调函数 的任意一种方式都会让对state
的更新生效(原文的做者使用了 fire这个词很是形象,想象一下这样的一种场景:你为了一个难题彻夜难眠,绞尽脑汁,忽然看到了火(黑暗前的黎明,激动)是但愿!!).若是你想基于上一个state
来设置state
,请阅读下方updater
的参数
解释:setSate
虽然是异步的,可是咱们仍是能够经过其余方式读取到生效的值,好比在react生命周期函数 componentDidUpdate
和 setState
的回调函数中读取 。言下之意是告诉咱们在 setState
完成后,会激活 componentDidUpdate
周期函数,有回调函数会执行回调函数。实例代码:
//DidUpdateOrCallback.js
state = {value:'default value'};
changeValue=()=>{
console.log(`Before change,value is ${this.state.value}`);
this.setState(
{value:'I have a new value'}
,()=>{
console.log(`Look at the value in setState callback function,value is ${this.state.value}`);
})
};
componentDidUpdate(){
console.log(`Look at the value in componentDidUpdate(),value is ${this.state.value}`);
}
//result:
Before change,value is default value
Look at the value in componentDidUpdate(),value is I have a new value
Look at the value in setState callback function,value is I have a new value 复制代码
setState()
will always lead to a re-render unless shouldComponentUpdate()
returns false
. If mutable objects are being used and conditional rendering logic cannot be implemented in shouldComponentUpdate()
, calling setState()
only when the new state differs from the previous state will avoid unnecessary re-renders.
翻译: setState
老是会触发重渲染,除非shouldComponentUpdate()
返回 false .shouldComponentUpdate()
不该该包含可变对象做为条件渲染的逻辑,咱们仅仅在state
发生变化去调用setSate
而避免没必要要的从新渲染
解释:shouldComponentUpdate()
的逻辑中直接比较引用类型是不能够发挥它的做用,就是说对于引用类型,地址老是相同,返回值永远为true
(浅比较).好比:
state = {value:{name:'default name'}};
shouldComponentUpdate(nextProps,nextState){
//value 是引用类型,比较的内存地址,浅比较 ,尝试直接比较name
let ret = (this.state.value === nextState.value);
console.log(`State.value is object ,so ret is always ${ret}.`);
return !ret;
}
changeValue=()=>{
let value = this.state.value;
value.name = 'I have a new name';
this.setState({value:value});
};复制代码
这里你会发现 ret 的值永远为 true,shouldComponentUpdate()老是返回 false,不会触发re-render.
The first argument is an updater
function with the signature:
(prevState, props) => stateChange复制代码
prevState
is a reference to the previous state. It should not be directly mutated. Instead, changes should be represented by building a new object based on the input from prevState
and props
. For instance, suppose we wanted to increment a value in state by props.step
:
翻译:prevState 是上一个状态的引用. 它不该该直接被改变。这种变化应该是基于 prevState
和 props
构建的一个新对象。好比,假如咱们想在state
中经过props.step
去对一个值作增量操做:
解释:无
this.setState((prevState, props) => {复制代码
return {counter: prevState.counter + props.step};复制代码
});复制代码
Both prevState
and props
received by the updater function are guaranteed to be up-to-date. The output of the updater is shallowly merged with prevState
.
翻译: updater function
保证接受到的prevState
和props
是最新的(这里的最新是相对于上次 render
后的值,而不是连续调用setState
的值,这里可能会让有些人有点误解)。调用updater function
是浅合并(这里有故事)
解释:无
The second parameter to setState()
is an optional callback function that will be executed once setState
is completed and the component is re-rendered. Generally we recommend using componentDidUpdate()
for such logic instead.
翻译:第二个是可选的回调函数,它会在setState
完成后而且组件从新渲染后马上执行。通常来讲,咱们推荐使用componentDidUpdate()
来替换这个逻辑。
解释: 若是使用回调函数,React 更建议在componentDidUpdate
来处理这个逻辑。就是这个回调函数在没有特别必要的状况下不要使用(源码对callback作了不少逻辑处理,后面也会说起)
You may optionally pass an object as the first argument to setState()
instead of a function:
setState(stateChange[, callback])复制代码
翻译:你能够有选择性的传递一个对象做为setState
的第一参数
解释: 除了传递函数以外也可使用对象做为参数
This performs a shallow merge of stateChange
into the new state, e.g., to adjust a shopping cart item quantity:
this.setState({quantity: 2})复制代码
翻译:它会执行浅合并来生成一个新的state
,好比说:修改购物车里的商品数量
This form of setState()
is also asynchronous, and multiple calls during the same cycle may be batched together. For example, if you attempt to increment an item quantity more than once in the same cycle, that will result in the equivalent of:
Object.assign(复制代码
previousState,复制代码
{quantity: state.quantity + 1},复制代码
{quantity: state.quantity + 1},复制代码
...复制代码
)复制代码
翻译:这种形式的 setState()
(把对象做为参数)也是"异步"的,相同周期(这个cycle的翻译我还没找到合适的词,暂且使用周期,好比同一个函数屡次调用setState
,咱们就认为他们在同一个周期)的屡次调用会被批量执行。好比,若是你试图在同一周期屡次增长商品的数量,那么它的结果等同于:
解释:这里的例子很是关键,要理解它必须彻底理解Object.assign
合并对象的原理,好比说,不一样对象相同属性,后面的对象会覆盖前面的对象;不一样对象不一样属性,会合并到最终的对象上,这里也写了一个demo:
state = {numberFunction:0, numberObject: 0};
changeNumberObject=()=>{
this.setState(
{numberObject:this.state.numberObject+1}
);
this.setState(
{numberObject:this.state.numberObject+1}
);
this.setState(
{numberObject:this.state.numberObject+1}
);
this.setState(
{numberObject:this.state.numberObject+1}
);
//只有最后这个setState才生效
};
changeNumberFunction=()=>{
this.setState((preState)=>{
return {numberFunction:preState.numberFunction+1}
})
this.setState((preState)=>{
return {numberFunction:preState.numberFunction+1}
})
this.setState((preState)=>{
return {numberFunction:preState.numberFunction+1}
})
this.setState((preState)=>{
return {numberFunction:preState.numberFunction+1}
})
//每一个都回执行
};
componentDidUpdate(){
console.log(`The expected numberObject is 4,real value is ${this.state.numberObject}`);
console.log(`The expected numberFunction is 4,real value is ${this.state.numberFunction}`);
}
复制代码
Subsequent calls will override values from previous calls in the same cycle, so the quantity will only be incremented once. If the next state depends on the previous state, we recommend using the updater function form, instead:
this.setState((prevState) => {复制代码
return {quantity: prevState.quantity + 1};复制代码
});复制代码
翻译:在同一周期靠后的setState()
将会覆盖前一个setSate()
的值(相同属性名),所以,这个商品数量仅自增了一次,若是但愿下一个state依赖上一个state,咱们推荐使用函数的形式
解释:这里很明显的告诉咱们,setSate
第一参数传递的对象或函数,react的处理方式不同, 这跟React在性能优化有很大关系,为了最小可能性去re-render(重渲染),React源码做了不少额外的工做
至此,官方文档对setState()
的概要描述已经结束。
系列文章持续更新.....
系列文章一:基于React源码深刻浅出setState:setState的异步实现
本文全部代码,请移步 :github
若是喜欢,不要吝啬你的 star .