[翻譯&摘抄] React 未來之函數式 setState

原文地址:Functional setState is the future of React
原文作者:Justice Mba
譯文出自:掘金翻譯計劃
原文鏈接:https://juejin.im/post/58cfcf6e44d9040068478fc6/
譯者:reid3290
校對者:sunui,imink

溫故知新

1、React 是一個基於組件的 UI 庫,組件基本上可以看作是一個接受某些屬性然後返回 UI 元素的函數。

2、React 提供了一個用於管理 state 的特殊函數 —— setState()。

3、setState() 的作用機制:你傳遞給它一個對象,該對象含有 state 中你想要更新的部分。

敲黑板,劃重點

setState() 不僅能接受一個對象,還能接受一個函數作爲參數。該函數接受該組件前一刻的 state 以及當前的 props 作爲參數,計算和返回下一刻的 state。

this.setState(function (state, props) {
 return {
  score: state.score - 1
 }
});

好奇寶寶要問了,這麼做的目的是什麼?

理由是,state 的更新可能是異步的。

React 在更新 State 的時候發生了什麼?》
React 首先會將你傳遞給 setState() 的參數對象合併到當前 state 對象中,然後會啓動所謂的 reconciliation,即創建一個新的 React Element tree(UI 層面的對象表示),和之前的 tree 作比較,基於你傳遞給 setState() 的對象找出發生的變化,最後更新 DOM。

但是,React 不會僅僅簡單地 “set-state”。因爲涉及到的工作量比較大,調用 setState() 並不一定會即時更新 state 》React 可能會將多次 setState() 調用批處理(batch)爲一次 state 的更新。

也就是說,React 並不會按照 setState() 的調用順序即時更新 state,而是首先會將所有對象合併到一起,然後僅用該對象進行一次 “set-state”。

如果用戶高頻多次的setState,React 則會對這些操作進行批處理:即將每次調用 setState() 時傳遞給它的所有對象合併爲一個對象,然後用這個對象去做真正的 setState()。

那麼就意味着,下面這個函數執行的結果會是1,而不是我們希望的3。

...

state = {score : 0};

// 多次 setState() 調用
increaseScoreBy3 () {
    this.setState({score : this.state.score + 1});
    this.setState({score : this.state.score + 1});
    this.setState({score : this.state.score + 1});
}

...

需要搞清楚的是,給 setState() 傳遞對象本身是沒有問題的,問題出在當你想要基於之前的 state 計算出下一個 state 時還給 setState() 傳遞對象。這是不安全的!

讓函數式 setState 來完成這樣的任務

當你編寫函數式 setState 的時候,更新操作會形成一個任務隊列,稍後會按其調用順序依次執行。

核心概念是,使用函數式 setState,你可以傳遞一個函數作爲其參數,當執行該函數時,React 會將更新後的 state 複製一份並傳遞給它,這便起到了更新 state 的作用。基於上述機制,函數式 setState 便可基於前一刻的 state 來更新當前 state。

更進一步

函數式 setState 的強大之處 —— 在組件類外部聲明 state 的更新邏輯,然後在組件類內部調用之:

// 在組件類之外
function increaseScore (state, props) {
  return {score : state.score + 1}
}

class User{
  ...

// 在組件類之內
  handleIncreaseScore () {
    this.setState(increaseScore)
  }

  ...
}

這就叫做 declarative宣告式編程)!組件類不用再關心 state 該如何更新,它只須聲明它想要的更新類型即可。

設想如下場景:你有一些很複雜的組件,每個組件的 state 都由很多小的部分組成,基於 action 的不同,你必須更新 state 的不同部分,每一個更新函數都有很多行代碼,並且這些邏輯都存在於組件內部。不過有了函數式 setState,再也不用面對上述問題了!

並且,基於函數式 setState,你就可以將 state 的更新邏輯抽離爲一個模塊,然後在組件中引入和使用該模塊。讓代碼顯得小而美。

import {increaseScore} from "../stateChanges";

class User{
  ...

  // 在組件類之內
  handleIncreaseScore () {
    this.setState(increaseScore)
}

  ...
}
發佈了344 篇原創文章 · 獲贊 39 · 訪問量 31萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章