React のコンテキストは、props
を使わずに子コンポーネントに親のデータを渡す為に使います。これにより
複数のコンポーネントから成り立つコンポーネント間の
props
が簡単になる子が特定の親の下に置かれてるどうか確認できる
などの利点があります。
コンテキストを作るにはReact.createContext
を使います。これはデフォルトで渡されることになる値を引数として1つ受け取ります。
const Meta = React.createContext({title: 'blog title'});
このMeta
はオブジェクトでProvider
とConsumer
2つのコンポーネントを持っています。
まず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引数を渡してない場合は、デフォルトで行われる浅い比較の回数も減らせれます。