ReactのuseContextを使って、データをグローバルに扱えるようにしてみます。
サンプルコード
今回はLayer1、Layer2、Layer3というコンポーネントを用意して、Layer1からLayer2、Layer2からLayer3をインポートする例で試してみます。
まずは使用前の例で、propsを使ってデータの受け渡しをしてみます。
Layer1.jsx
1 2 3 4 5 6 7 8 9 10 11 12 13 | import Layer2 from './Layer2.jsx' function Layer1() { const text = "sample" ; return ( <div style={{border: "2px solid red" , padding: "10px" }}> <p>Layer1</p> <Layer2 text={text} /> </div> ) } export default Layer1 |
Layer2.jsx
1 2 3 4 5 6 7 8 9 10 11 12 | import Layer3 from './Layer3.jsx' function Layer2({text}) { return ( <div style={{border: "2px solid blue" , padding: "10px" }}> <p>Layer2</p> <Layer3 text={text} /> </div> ) } export default Layer2 |
Layer3.jsx
1 2 3 4 5 6 7 8 9 10 | function Layer3({text}) { return ( <div style={{border: "2px solid green" , padding: "10px" }}> <p>Layer3</p> <p>{text}</p> </div> ) } export default Layer3 |
このようにpropsを使ってデータの受け渡しができますが、バケツリレーとなるため深い階層のコンポーネントだと記述が助長になりやすいです。
propsの場合のデモページ
useContextを使うことで、コンポーネント間のデータの受け渡しがしやすくなります。
まずLayer1.jsxでcreateContextを使ってコンテクストを作成して、使用したいコンポーネントをコンテクストプロバイダで囲います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | import { createContext } from 'react' import Layer2 from './Layer2.jsx' export const Text = createContext( null ); function Layer1() { return ( <Text.Provider value= "sample" > <div style={{border: "2px solid red" , padding: "10px" }}> <p>Layer1</p> <Layer2 /> </div> </Text.Provider> ) } export default Layer1 |
今回の場合はTextにコンテクストを作成しているため、使用したいコンポーネント(Layer2)をコンテクストプロバイダ(Text.Provider)で囲い、valueに渡す値を設定しています。
間に入るLayer2.jsxには特に必要な追加はありません。
propsの記述だけ除去しておきます。
1 2 3 4 5 6 7 8 9 10 11 12 | import Layer3 from './Layer3.jsx' function Layer2() { return ( <div style={{border: "2px solid blue" , padding: "10px" }}> <p>Layer2</p> <Layer3 /> </div> ) } export default Layer2 |
最後にLayer3.jsxで受け取る設定を追加します。
Layer1からTextをインポートして、useContextで値を取り出します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | import { useContext } from 'react' import { Text } from './Layer1' function Layer3() { const text = useContext(Text); return ( <div style={{border: "2px solid green" , padding: "10px" }}> <p>Layer3</p> <p>{text}</p> </div> ) } export default Layer3 |
これでLayer1からLayer3に直接データの受け渡しができました。
useContextの場合のデモページ
次にuseStateを使って渡したデータの更新を試してみます。
Layer1.jsxを以下のように変更します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | import { createContext, useState } from 'react' import Layer2 from './Layer2.jsx' export const Text = createContext( null ); function Layer1() { const [message, setMessage] = useState( "sample" ); return ( <Text.Provider value={message}> <div style={{border: "2px solid red" , padding: "10px" }}> <p>Layer1</p> <input type= "text" value={message} onChange={e => setMessage(e.target.value)} /> <Layer2 /> </div> </Text.Provider> ) } export default Layer1 |
useStateを使った形に変更して、Layer1から値を更新できるようにしました。
useStateを使うデモページ
次はuseContextを複数使用する場合を試してみます。
入れ子で囲うようにするといいようです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | import { createContext, useState } from 'react' import Layer2 from './Layer2.jsx' export const Text = createContext( null ); export const Label = createContext( null ); function Layer1() { const [message, setMessage] = useState( "sample" ); const [message2, setMessage2] = useState( "test" ); return ( <Text.Provider value={message}> <Label.Provider value={message2}> <div style={{border: "2px solid red" , padding: "10px" }}> <p>Layer1</p> <input type= "text" value={message} onChange={e => setMessage(e.target.value)} /> <input type= "text" value={message2} onChange={e => setMessage2(e.target.value)} /> <Layer2 /> </div> </Label.Provider> </Text.Provider> ) } export default Layer1 |
Layer3.jsxで追加した分も読み込むように変更します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | import { useContext } from 'react' import { Text, Label } from './Layer1' function Layer3() { const text = useContext(Text); const label = useContext(Label); return ( <div style={{border: "2px solid green" , padding: "10px" }}> <p>Layer3</p> <p>{text}</p> <p>{label}</p> </div> ) } export default Layer3 |
これで複数のデータの受け渡しができました。
複数データを使用するデモページ
最後にcreateContextの引数についてですが、これはコンテクストプロバイダ(Text.Provider)がない場合の初期値になります。
Text.Providerをなくして試してみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | import { createContext } from 'react' import Layer2 from './Layer2.jsx' export const Text = createContext( 'default' ); function Layer1() { return ( <div style={{border: "2px solid red" , padding: "10px" }}> <p>Layer1</p> <Layer2 /> </div> ) } export default Layer1 |
これで試してみると、createContextの引数で設定したdefaultが表示されるのが確認できました。
コンテクストプロバイダがない場合のデモページ
コメントが承認されるまで時間がかかります。