iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 6
0
Modern Web

關於React,那些我不知道的系列 第 6

實現跨元件資料共享, useContext

  • 分享至 

  • xImage
  •  

Why
過往,我們為了避免 props 過度傳遞(Prop Drilling)往下太多層, 或是需要跨多個元件,共享資料。
我們往往會使用 React Context 來共享資料。

How
Show me the code
Codesandbox Demo

先說說 React context 如何使用?

  1. 我們需要有個 Context Provider 包住我們那些可以共享狀態的元件。
  2. 進入底下需要使用這些狀態的元件,呼叫 Context 取得共享狀態,今天得益於 hooks 的產生,我們可以使用 useContext

過往是透過 Context Consumer 這個元件取得共享狀態,

假設我們想建立一個有主題( Light / Dark theme )樣式的全域共享狀態,實作方法如下

  1. 建立我們的<ThemeProvider> 元件,提供給整個 App 使用
  2. 需要有兩個狀態被共享,(1). 當前 theme 樣式 (2). 切換 theme 的 handler
  3. 在需要使用 theme 的地方,用 useContext 呼叫取得

主題們的實際樣式

const themes = {
  light: {
    foreground: "#000000",
    background: "#eeeeee"
  },
  dark: {
    foreground: "#ffffff",
    background: "#222222"
  }
};

建立、定義 Context 需要儲存的資料與預設值

export const ThemeContext = React.createContext({
  theme: themes.dark,
  toggleTheme: () => {}
});

建立 Provider 元件,與實作切換 theme 的狀態,並且提供這個 theme 給 Provider。

const ThemeProvider = ({ children }) => {
  const [dark, setDark] = useState(true);
  const toggleTheme = () => setDark(!dark);
  const theme = dark ? themes.dark : themes.light;
  const defaultValue = {
    toggleTheme,
    theme
  };
  return (
    <ThemeContext.Provider value={defaultValue}>
      {children}
    </ThemeContext.Provider>
  );
};

export default ThemeProvider;

在 index.js 內用<ThemeProvider> 元件,把整個 App 包裹起來,供應全站分享主題樣式。

   <ThemeProvider>
      <App />
   </ThemeProvider>

在 App.js 中,套用全站樣式,透過 useContext 取得我們 theme 的共享資料。
useContext(ThemeContext)。 hook 中需要帶入一個參數,也就是指我們需要取得哪個共享資料的 Context (我們可以有許多不同的 Context )

 const { theme } = useContext(ThemeContext);
  return (
    <div
      className="App"
      style={{
        color: theme.foreground,
        backgroundColor: theme.background
      }}
    >
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
      <ThemeButton />
    </div>
  );

在需要呼叫 toggleTheme 的地方,也使用 useContext(ThemeContext)

const ThemeButton = () => {
  const { toggleTheme } = useContext(ThemeContext);
  return <button onClick={toggleTheme}>切換深夜模式</button>;
};

如此我們便完成了 useContext 的練習。
Codesandbox Demo

注意:我們的 <App><ThemeButton> 都沒有透過 props 來取得 theme 跟 toggleTheme 這兩個狀態。

以下是個在 index.js 當中常見到的 pattern,我們將不同性質的狀態分散在不同的 Provider,實現關注點分離 (Separation of concerns),使我們的程式碼比較好維護。

      <ThemeProvider>
        <SnackbarProvider>
          <AuthProvider>
            <ApiProvider>
              <App />
            </ApiProvider>
          </AuthProvider>
        </SnackbarProvider>
      </ThemeProvider>

參考資料

Toggle theme using React Hooks
Reactjs
透過 React CreateContext 搭配 React useContext 與 useReducer 來做 Global State Manager
Prop Drilling


上一篇
所以昨天說的那個 useCallback 是幹啥用的? 效能優化? 來瞧瞧
下一篇
狀態管理的救星?! Recoil 官網導讀( 1 ) 動機
系列文
關於React,那些我不知道的30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言