做者 : 墨成 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 .