精讀《如何安全地使用 React context》

本期精讀文章是:How to safely use react context

1 引言

在 React 源碼中,context 始終存在,卻在 React 0.14 的官方文檔中才有所體現。在目前最新的官方文檔中,仍不建議使用 context,也表明 context 是一個實驗性的 API,在未來 React 版本中可能被更改。那麼哪些場景下需要用到 context,而哪些情況下應該避免使用,context 又有什麼坑呢?讓我們一起來討論一下。

2 內容概要

React context 可以把數據直接傳遞給組件樹的底層組件,而無需中間組件的參與。Redux 作者 Dan Abramov 為 contenxt 的使用總結了一些注意事項:

  • 如果你是一個庫的作者,需要將信息傳遞給深層次組件時,context 在一些情況下可能無法更新成功。
  • 如果是界面主題、本地化信息,context 被應用於不易改變的全局變數,可以提供一個高階組件,以便在 API 更新時只需修改一處。
  • 如果庫需要你使用 context,請它提供高階組件給你。

正如 Dan 第一條所述,在 React issue 中,經常能找到 React.PureComponent、shouldComponentUpdate 與包含 Context 的庫結合後引發的一些問題。原因在於 shouldComponentUpdate 會切斷子樹的 rerender,當 state 或 props 沒有發生變化時,可能意外中斷上層 context 傳播。也就是當 shouldComponentUpdate 返回 false 時,context 的變化是無法被底層所感知的。

因此,我們認為 context 應該是不變的,在構造時只接受 context 一次,使用 context,應類似於依賴注入系統來進行。結合精讀文章的示例總結一下思路,不變的 context 中包含可變的元素,元素的變化觸發自身的監聽器實現底層組件的更新,從而繞過 shouldComponentUpdate。

最後作者提出了 Mobx 下的兩種解決方案。context 中的可變元素可用 observable 來實現,從而避免上述事件監聽器編寫,因為 observable 會幫你完成元素改變後的響應。當然 Provider + inject 也可以完成,具體可參考精讀文章中的代碼。

3 精讀

本次提出獨到觀點的同學有:@monkingxue @alcat2008 @ascoders ,精讀由此歸納。

context 的使用場景

In some cases, you want to pass data through the component tree without having to pass the props down manually at every level.

context 的本質在於為組件樹提供一種跨層級通信的能力,原本在 React 只能通過 props 逐層傳遞數據,而 context 打破了這一層束縛。

context 雖然不被建議使用,但在一些流行庫中卻非常常見,例如:react-redux、react-router。究其原因,我認為是單一頂層與多樣底層間不是單純父子關係的結果。例如:react-redux 中的 Provider,react-router 中的 Router,均在頂層控制 store 信息與路由信息。而對於 Connect 與 Route 而言,它們在 view 中的層級是多樣化的,通過 context 獲取頂層 Provider 與 Router 中的相關信息再合適不過。

context 的坑

  • context 相當於一個全局變數,難以追溯數據源,很難找到是在哪個地方中對 context 進行了更新。
  • 組件中依賴 context,會使組件耦合度提高,既不利於組件復用,也不利於組件測試。
  • 當 props 改變或是 setState 被調用,getChildContext 也會被調用,生成新的 context,但 shouldComponentUpdate 返回的 false 會 block 住 context,導致沒有更新,這也是精讀文章的重點內容。

4 總結

正如精讀文章開頭所說,context 是一個非常強大的,具有很多免責聲明的特性,就像伊甸園中的禁果。的確,引入全局變數似乎是應用混亂的開始,而 context 與 props/state 相比也實屬異類。在業務代碼中,我們應抵制使用 context,而在框架和庫中可結合場景適當使用,相信 context 也並非洪水猛獸。

討論地址:精讀《How to safely use React context》- Issue #23 - dt-fe/weekly

如果你想參與討論,請 點擊這裡 ,每周都有新的主題,每周五發布。

推薦閱讀:

ES6--擴展運算符與剩餘操作符
js中的觀察者模式具體是指什麼,怎麼感覺就好像是模塊化開發的一個分支?
前端leader們如何安排面試?
ELSE技術周刊(2017.06.26期)

TAG:JavaScript | React | 前端开发 |