React のコンテキストは、propsを使わずに子コンポーネントに親のデータを渡す為に使います。これにより
複数のコンポーネントから成り立つコンポーネント間の
propsが簡単になる子が特定の親の下に置かれてるどうか確認できる
などの利点があります。
コンテキストを作るにはReact.createContextを使います。これはデフォルトで渡されることになる値を引数として1つ受け取ります。
const Meta = React.createContext({title: 'blog title'});このMetaはオブジェクトでProviderとConsumer2つのコンポーネントを持っています。
まずProviderは渡すデータを置くために使います。データはこの要素のvalue属性に渡します。
次にConsumerは渡ってきた値を受け取る為の要素です。Consumerは上位階層にProviderがある時、一番近いそれに渡された値を受け取りますが、もしProviderが1つも無い場合、コンテキストを作る時に渡したデフォルト値を受け取ります。注意なのがこのコンポーネントのchildrenはデータを引数に受け取る関数だという点です。
例です。この例はProviderと通す時と通さない時の動作を見れるもので、それぞれpropsで何も値を渡していないのにapp title、blog titleと別の内容が表示されます。
const Meta = React.createContext({ title: "blog title" });
const Title = () => {
return (
{meta => {
return {meta.title}
;
}}
);
};
const App = () => {
return (
<>
>
);
}useContext
const Meta = React.createContext({ title: "blog title" });
const Title = () => {
const meta = React.useContext(Meta);
return {meta.title}
;
};
export default function App() {
return (
<>
>
);
}useContextへはConsumerを渡すわけではなくコンテキストそのものを渡します。
考察
memo化されたコンポーネントの中でuseContextを使っていると、Contextの値を更新してもそのコンポーネントは再レンダリングされません。このことからContextの全ての値を更新することはオススメしないです。
僕的にはContextへは何かキーの下にぶら下がれるオブジェクト値などを格納すると良いと思います。例えば以下のような感じです。
const contextValues = {
'/': {
title: 'Top Page',
description: '...'
},
'/foo': {
title: 'Foo Page',
description: '...'
},
}そしてこのキー(path)だけ Flux で管理して必要に応じてuseContextを使っているコンポーネントに渡します。コンポーネントの中では渡されたpathを使いuseContextから値を取り出して使います。
const {title, description} = useContext(XxContext)[path];このようにすることでmemo化されていても値を更新できますし、その第2引数を渡してない場合は、デフォルトで行われる浅い比較の回数も減らせれます。