useContext Hook 是如何工作的

  • 2019 年 10 月 5 日
  • 筆記

所有這些新的React Hook之間都有一個宗旨:就是為了使函數組件像類組件一樣強大。

useContext hook 與其它幾個有點不一樣,但它在特定場景下還是很有用的。

React 的 Context API 是一種在應用程式中深入傳遞數據的方法,而無需手動一個一個在多個父子孫之間傳遞 prop。當咱們需要的只是傳遞數據時,它可以作為像Redux這樣的工具的一個很好的替代。

使用 Context ,首先頂層先聲明 Provier 組件,並聲明 value 屬性,接著在後代組件中聲明 Consumer 組件,這個 Consumer 子組件,只能是唯一的一個函數,函數參數即是 Context 的負載。如果有多個 Context ,ProviderConsumer 任意的順序嵌套即可。

此外我們還可以針對任意一個 Context 使用 contextType 來簡化對這個 Context 負載的獲取。但在一個組件中,即使消費多個 Context,contextType 也只能指向其中一個。

Hooks 環境中,依舊可以使用 Consumer,但是 ContextType 作為類靜態成員肯定是用不了。Hooks 提供了 useContext,不但解決了 Consumer 難用的問題同時也解決了 contextType 只能使用一個 context 的問題。

標準方式

使用 API的典型方法如下所示:

import React from "react";  import ReactDOM from "react-dom";    // 創建 Context  const NumberContext = React.createContext();  // 它返回一個具有兩個值的對象  // { Provider, Consumer }    function App() {    // 使用 Provider 為所有子孫代提供 value 值    return (      <NumberContext.Provider value={42}>        <div>          <Display />        </div>      </NumberContext.Provider>    );  }    function Display() {    // 使用 Consumer 從上下文中獲取 value    return (      <NumberContext.Consumer>        {value => <div>The answer is {value}.</div>}      </NumberContext.Consumer>    );  }    ReactDOM.render(<App />, document.querySelector("#root"));

可以 CodeSandbox上看看運行效果。

使用 useContext 方式

使用 useContext hook 來重寫上面的示例

import React, { useContext } from 'react';    // ...    function Display() {    const value = useContext(NumberContext);    return <div>The answer is {value}.</div>;  }

調用useContext,傳入從React.createContext獲取的上下文對象。

唯一需要注意的是你必須將整個上下文對象傳遞給useContext – 而不僅僅是Consumer, 當然如果忘記了,React會給出警告。

嵌套的 Consumers

你可能遇到這樣的情況,咱們的組件需要從多個父上下文中接收數據,從而導致這樣的程式碼

function HeaderBar() {    return (      <CurrentUser.Consumer>        {user =>          <Notifications.Consumer>            {notifications =>              <header>                Welcome back, {user.name}!                You have {notifications.length} notifications.              </header>            }        }      </CurrentUser.Consumer>    );  }

這種大量嵌套只是為了接收兩個值。下面是使用useContext時的效果:

function HeaderBar() {    const user = useContext(CurrentUser);    const notifications = useContext(Notifications);      return (      <header>        Welcome back, {user.name}!        You have {notifications.length} notifications.      </header>    );  }

總結

useContext 接收一個 context 對象(React.createContext 的返回值)並返回該 context 的當前值。當前的 context 值由上層組件中距離當前組件最近的 <CountContext.Provider>value prop 決定。

當組件上層最近的 <CountContext.Provider> 更新時,該 Hook 會觸發重渲染,並使用最新傳遞給 CountContext provider 的 context value 值。

別忘記 useContext 的參數必須是 context 對象本身:

  • 正確: useContext(MyContext)
  • 錯誤: useContext(MyContext.Consumer)
  • 錯誤: useContext(MyContext.Provider)

調用了 useContext 的組件總會在 context 值變化時重新渲染。如果重渲染組件的開銷較大,你可以 通過使用 memoization 來優化。

程式碼部署後可能存在的BUG沒法實時知道,事後為了解決這些BUG,花了大量的時間進行log 調試,這邊順便給大家推薦一個好用的BUG監控工具 Fundebug

參考:

https://daveceddia.com/usecon…