contextとは
コンポーネントツリーを越えてデータを共有する方法です。 子コンポーネントの深さが深まると、引き続けてState管理のためにpropsを渡さなければならない状況になってしまいます。 そのようなことを解決するためにcontext apiを提供します。 contextを利用すれば、コンポーネントツリー全体にデータを提供することができます。(props drillingを防ぐ) グローバルなデータを共有する必要があるときに使用!contextの流れ
1. create Contextメソッドを使ってcontextを生成する。2. 生成されたcontextを持ってcontext providerでコンポーネントツリーを包む。
3. value propを使ってcontext providerに希望する値を入力する。
4. context consumerにて必要なコンポーネントからその値を読み込む。
contextの例
import React from 'react'
export const themes = {
light: {
foreground: '#000000',
background: '#eeeeee',
},
dark: {
foreground: '#ffffff',
background: '#222222',
},
}
export const ThemeContext = React.createContext(themes.dark);
React.createContext()を使って、共有したいデータを定義します。
これはthemes.darkをdefaultValueとして使うと言う定義になります。
defaultValueとはあるコンポーネントがProviderを探せない(親子関係❌)時に使う値です。
import React, { Component } from 'react'
import { ThemeContext } from './ThemeContext';
class ThemedButton extends Component {
render() {
let props = this.props;
let theme = this.context;
return (
<button
{...props}
onClick={props.changeTheme}
style={{ backgroundColor: theme.background, color: theme.foreground }}>
button1
</button>
);
}
}
ThemedButton.contextType = ThemeContext;
export default ThemedButton;
React.createContext()で生成したContextオブジェクト(ThemeContext)を
希望するクラスのcontextTypeプロパティに指定できます。
このプロパティを活用して、クラス内でthis.contextを利用して該当Contextの最も近いProviderを探してその値を読むことができるようになります。
import React, { Component } from 'react'
import { ThemeContext, themes } from './ThemeContext';
import ThemedButton from './ThemedButton';
export default class Example extends Component {
constructor(props) {
super(props);
this.state = {
theme: themes.light,
};
this.toggleTheme = () => {
this.setState((prev) => ({
theme: prev.theme === themes.dark ? themes.light : themes.dark,
}));
};
}
render() {
return (
<div>
<ThemeContext.Provider value={this.state.theme}>
<ThemedButton changeTheme={this.toggleTheme} />
<ThemeContext.Consumer>
{(theme) => (
<div
style={{
height: 300,
width:300,
backgroundColor: theme.background,}}
></div>
)}
</ThemeContext.Consumer>
</ThemeContext.Provider>
<ThemedButton />
</div>
);
}
}
<ThemeContext.Provider value={this.state.theme}>
で囲まれている
<ThemedButton>
のbackgroundColorはProvider value propsにより、backgroundColorは”light”になります。Providerはvalue propを受けてこの値を下位にあるコンポーネントに転送するためです。下位のThemedButtonをクリックすると、toggleThemeによって、backgroudColorが変わります。
<Context.Consumer>
のthemeパラメータは、該当contextのProviderの中で上位ツリーから最も近いProviderのvaluepropと同じです。なので、<ThemedButton>
と<Context.Consumer>
のbackgroundColorは共有され、いつも同じです。
一番下の<ThemedButton />
は<ThemeContext.Provider>
に囲まれていなため、
ThemeContext.jsの以下のロジックにより、いつもbackgroundColorはdarkです。
export const ThemeContext = React.createContext(themes.dark);
useContext Hook
useContextとは、contextオブジェクト(React.createContextで返還された値)を受け、そのcontextの現在の値を返還します。 class componentでは、this.contextの形でThemeContextの値を受けましたが、 function componentでは、useContextを使って、以下のように使うことが可能です。import React from 'react'
import { useContext } from 'react'
import { ThemeContext } from './ThemeContext'
export default function ThemedButton(props) {
const theme = useContext(ThemeContext)
return (
<button
{...props}
onClick={props.changeTheme}
style={{ backgroundColor: theme.background, color: theme.foreground }}>
button1
</button>
)
}