この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
こんにちは、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で動作を試してみます。
src/App.tsx
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を複数回使った場合はどうでしょう。
src/App.tsx
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が使われていない場合はどうなるでしょう。
src/App.tsx
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の引き渡しを記述しなければならず、記述量という点では大分違いがありますね。
src/App.tsx
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なデータ共有をとてもシンプルに行えるようになったことが分かります。是非とも活用したいですね。
参考
以上