はじめに
現場でContextを使った実装を任された際に手こずった(現在進行形)ので、もっと単純化してContextの使い方を習得しようという意図をもって作成したものについて備忘録を残します。
本来であればTypescriptで書くべきなのですが、そちらも初学者のため、今回はjavascriptを使って書いています。
Contextとは?
リファレンスを見てみましょう。
「コンテクストを用いると、コンポーネントは props を渡すことなく、離れた親要素から情報を取得できるようになります。例えば、アプリの最上位のコンポーネントが、現在の UI テーマをコンポーネントの階層に関係なくすべてのコンポーネントに渡すことができます。」
説明は上記の通りなのですが、
Context
を使わない場合、props
で「親→子→孫」のように下のコンポーネントに情報を渡していくことになります。しかしこれにはデメリットがあります。
・propsを親から受けて孫に渡すという役割を持つコンポーネントが出来る。
・コンポーネント階層が深くなるとコードが読みにくく、保守性が低下する。
そしてこれらを解決してくれるのが今回のContext
ということになります。
さっそく作ってみた
今回はContextで管理された値を画面に表示する機能を実装していきます。
完成形はこんな感じ。
①作成したコンポーネント
import { Form } from "./Form";
import { TextContainer } from "./TextContainer";
import { TextProvider } from "./TextProvider";
export const App = () => {
return (
<div>
<TextProvider>
<Form />
<TextContainer />
</TextProvider>
</div>
);
};
TextProvider:Contextを作成し、値を渡す
Form:テキストボックスとボタン
TextContainer:Contextで管理されている値を表示
②Contextの作成
import { createContext, useState } from "react";
//コンテキストの作成
export const Text = createContext();
export const TextProvider = ({ children }) => {
const [texts, setTexts] = useState([]);
//Formコンポーネントのテキストボックスの内容を配列textsに追加する
const addText = (inputValue) => {
setTexts((prev) => [...prev, inputValue]);
};
//Providerコンポーネントで子コンポーネントを包むことで、Provider配下で利用するコンテキストを決定
return <Text.Provider value={{ texts, addText }}>{children}</Text.Provider>;
};
まずContextオブジェクトを作成する必要があり、その際にはcreateContext
を使用します。
引数は初期値を入れることが出来ます。
//コンテキストの作成
export const Text = createContext();
次に子孫コンポーネントで値を利用できるように、Provider
で子コンポーネントを包んであげます。
[作成したコンテキストオブジェクト名].Provider value={渡したい値}
という形式で記載し、value
には子孫コンポーネントに渡したい値を書いてあげます。
今回は動的に変化する値を画面に表示させたいのでState
で管理している値を渡しています。
//Providerコンポーネントで子コンポーネントを包むことで、Provider配下でコンテキストが利用出来る
return <Text.Provider value={{ texts, addText }}>{children}</Text.Provider>;
③値を画面に表示させる
import { useContext } from "react";
import { Text } from "./TextProvider";
export const TextContainer = () => {
//渡された値を使用する
const { texts, addText } = useContext(Text);
return (
<div>
{texts.map((text, index) => {
return (
<div>
<p>
<span>{index + 1}.</span>
{text}
</p>
</div>
);
})}
</div>
);
};
渡されたコンテキストの値を子孫コンポーネント側で使用するためにはuseContext
を使います。
useContext(作成したコンテキストオブジェクト名)
という形式で使用し、渡された値を受け取ることが出来ます。
//渡された値を使用する
const { texts, addText } = useContext(Text);
注意
作成したContextオブジェクトのimportも忘れずにしましょう。
こんなことで時間が溶けてしまいました、、、
import { Text } from "./TextProvider";
④テキストボックスとボタンの作成
import { useContext, useState } from "react";
import { Text } from "./TextProvider";
export const Form = () => {
const { texts, addText } = useContext(Text);
const [value, setValue] = useState();
const onChangeText = (e) => {
setValue(e.target.value);
};
const handleClick = (value) => {
addText(value);
setValue("");
};
return (
<div>
<input value={value} onChange={onChangeText} />
<button
onClick={() => {
handleClick(value);
}}
>
追加
</button>
</div>
);
};
Contextで管理されているaddText
を使用するためにuseContext
を使って値を受け取っています。