こんにちは、株式会社カケハシでおくすり連絡帳 Pocket Musubiの開発を担当している渡辺です。 以前はMusubiをはじめ各種プロダクトのフロントエンド部分をAngularで書いていたのですが、最近はもっぱらReact/Next.jsを扱うことが増えました。 現在、Reactのキャッチアップに励んでいる日々です。
最近、関わっているプロダクトのコードでuseContextというhooksが利用されているのをみて、興味を持ちました。 調べたことをブログの記事にしたいと思います。 かなり初心者向けの話になると思いますが、ご容赦ください。
Contextってなんだろう
Contextは何かというと、異なるコンポーネント間でデータを簡単に共有し、コンポーネントツリー内でグローバルな状態を管理できるものです。 Reactといえば、コンポーネントにデータを渡すときにpropsでの値の引き渡しを使いますが、これを使わないので、シンプルにデータを共有できます。コンポーネント同士も疎結合になるのも良いですね。
Contextは
- createContextでcontextを作成する
- Contextの値の呼び出しはuseContext()を利用する
- Context.Provider配下ではContextの値を呼び出せる
という方法で使います。 useContextというフックを利用することにより、コンポーネントツリーのどこからでもデータにアクセスできます。
試しに書いてみる
自分自身を保存するContextを作成してみます。 以下がサンプルです。
"use client"; import React, { createContext, useContext, useState } from "react"; type MeContextType = { me: string; setMe: (me: string) => void; }; const MeContext = createContext({} as MeContextType); type Props = { children: React.ReactNode }; export const MeContextProvider: React.FC<Props> = ({ children }) => { const [me, setMe] = useState(""); return ( <MeContext.Provider value={{ me, setMe }}>{children}</MeContext.Provider> ); }; export const useMe = () => useContext(MeContext);
こんな感じになりました。 createContextでContextを作成し、useContextでアクセス可能にしてます。
次に使う側です。
export default function Home() { return ( <MeContextProvider> <FirstComponent /> </MeContextProvider> ); }
"use client"; import { useMe } from "@/hooks/useMe"; import { NextPage } from "next"; export const FirstComponent: NextPage = () => { const { me, setMe } = useMe(); setMe("sassy"); return ( <> <div>{me}</div> </> ); };
useMeを利用することにより、文字列を設定したり参照したりします。 どうでしょう。簡単ですね。
状態管理に使う
状態管理では、Reduxを使うという選択肢もありますね。 Reduxは、大規模なアプリケーションでの複雑な状態管理に向いているようですが、小規模なアプリケーションや単純な状態管理にはやや冗長です。 useContextはReduxよりもシンプルに書けるので、小規模なアプリケーションや単純な状態管理にはuseContextの方が使いやすいかもしれません。
パフォーマンス
Reactはコンポーネントの状態が変更されるたびに再レンダリングを実行します。 useContextを使用する場合、コンテキストの変更が関連するコンポーネント全体に再レンダリングを引き起こす可能性があります。ここは注意が必要ですね。 できる限り再レンダリングを行わないように利用する工夫が必要です。 ここら辺の勘所もナレッジをためていきたいですね。
ここまでuseContextとは何なのかのさわりを書いてみました。 今後もReactの基本的なことを発信していけたらと思っています。