[React] useContextの使い方を改めて確認してみた
こんにちは、CX事業本部 IoT事業部の若槻です。
ReactでGlobalなデータ共有を実現できるライブラリはいくつかあるのですが、React hooksで既定で使えるuseContextでも同様のことは行なえます。
今回は、useContextの使い方を改めて確認してみました。
環境
- react@18.0.0
- typescript@4.6.3
useContextを使ってみる
useContextを使うことにより、Component treeのどの階層であっても、propsによる値の引き渡しを行うこと無く、Globalにデータの共有を行うことができます。
Function ComponentにおけるuseContextの使い方は次のようになります。
createContext
でContextを作成する。defaultValue
の指定は必須。<Context.Provider value=<value>>
でラップした配下のComponent内ではContextの値(value
)を呼び出せる。- Contextの値の呼び出しは
useContext
を使用する。
下記のApp -> Toolbar -> ThemedButton
というComponent treeで動作を試してみます。
import React, { useContext } from 'react'; const themes = { light: { foreground: '#000000', background: '#eeeeee', }, dark: { foreground: '#ffffff', background: '#222222', }, }; const ThemeContext = React.createContext(themes.light); const App = () => { return ( <> <ThemeContext.Provider value={themes.dark}> <Toolbar /> </ThemeContext.Provider> </> ); }; const Toolbar = () => { return ( <div> <ThemedButton /> </div> ); }; const ThemedButton = () => { const theme = useContext(ThemeContext); return ( <button style={{ background: theme.background, color: theme.foreground }}> I am styled by theme context! </button> ); }; export default App;
App
Componentで指定したthemes.light
の色データが、2階層下のThemedButton
Componentで使用できています。
Context Providerを複数回使った場合
Component tree内で同じContext Providerを複数回使った場合はどうでしょう。
const ThemeContext = React.createContext(themes.light); const App = () => { return ( <> <ThemeContext.Provider value={themes.dark}> <Toolbar /> </ThemeContext.Provider> </> ); }; const Toolbar = () => { return ( <div> <ThemeContext.Provider value={themes.light}> <ThemedButton /> </ThemeContext.Provider> </div> ); }; const ThemedButton = () => { const theme = useContext(ThemeContext); return ( <button style={{ background: theme.background, color: theme.foreground }}> I am styled by theme context! </button> ); };
この場合は、Contextを呼び出したComponentから最も近いContext Providerで指定された値が使用されます。
Context Providerを使わずにContextを呼び出した場合
Contextを呼び出したComponentのどの祖先ComponentでもContext Providerが使われていない場合はどうなるでしょう。
const ThemeContext = React.createContext(themes.light); const App = () => { return ( <> <Toolbar /> </> ); }; const Toolbar = () => { return ( <div> <ThemedButton /> </div> ); }; const ThemedButton = () => { const theme = useContext(ThemeContext); return ( <button style={{ background: theme.background, color: theme.foreground }}> I am styled by theme context! </button> ); };
この場合は、createContext
で指定されたdefaultValue
の値が使われます。
useContextを使わない場合
useContext
を使わずにComponent tree間での値の共有を行いたい場合、各Component間でpropsの引き渡しを記述しなければならず、記述量という点では大分違いがありますね。
import React from 'react'; const themes = { light: { foreground: '#000000', background: '#eeeeee', }, dark: { foreground: '#ffffff', background: '#222222', }, }; interface Theme { foreground: string; background: string; } const App: React.FC = () => { return ( <> <Toolbar foreground={themes.light.foreground} background={themes.light.background} /> </> ); }; const Toolbar: React.FC<Theme> = (theme) => { const { foreground, background } = theme; return ( <div> <ThemedButton foreground={foreground} background={background} /> </div> ); }; const ThemedButton: React.FC<Theme> = (theme) => { return ( <button style={{ background: theme.background, color: theme.foreground, }} > I am styled by theme context! </button> ); }; export default App;
おわりに
useContextの使い方を改めて確認してみました。
こうしてuseContextを使う場合と使わない場合とで比べてみると、useContextによりGlobalなデータ共有をとてもシンプルに行えるようになったことが分かります。是非とも活用したいですね。
参考
以上