1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ReactのuseContextってなに?

Posted at

useContextとは?

通常親コンポーネントから子コンポーネントにデータを渡す際はpropsを介して行います。しかし親から子、そのまた子といったように複数のコンポーネントを介してデータを渡す場合にpropsで渡すことが難しくなってきます。

useContextを使用することで、propsをコンポーネント間で渡すことなく全コンポーネント間でデータを共有することができます。

実際にuseContextを使ってコンポーネント間でデータを共有してみよう

ログイン画面で入力したユーザIDを、他の画面でも参照できるように Context 情報を共有する実装を考えました。

UserIdContext.tsx
import { createContext, useContext, useState, ReactNode } from "react";

// userIdとそれを更新する関数を持つContextを作成
// 初期値は undefined(Providerの外で使われるとエラーにするため)
const UserIdContext = createContext<
  { userId: string; setUserId: (u: string) => void } | undefined
>(undefined);

// ユーザーIDの状態を提供するProviderコンポーネント
export const UserIdProvider = ({ children }: { children: ReactNode }) => {
  const [userId, setUserId] = useState<string>(""); // userIdの状態管理

  console.log(userId); // 状態が変わるたびにログに出力(デバッグ用)

  return (
    <UserIdContext.Provider value={{ userId, setUserId }}>
      {children}
    </UserIdContext.Provider>
  );
};

// ContextからuserIdとsetUserIdを取り出すためのカスタムフック
export const useUserId = () => {
  const context = useContext(UserIdContext);

  // Contextがundefinedなら(=Providerの外から呼び出されたら)例外を投げる
  if (!context) throw new Error("useUserId must be used within UserIdProvider");

  return context;
};

ここで大事なのは
createContext で画面同士で共有したいステート(データ)を含んだ Context 情報を作成する。ここではユーザーIDを画面間で共有したいので userId ステートを Context に含める。

Context の値を更新するために必要な Provider コンポーネントを作成する。この Provider コンポーネントが更新された時に、Provider に渡している 最新のvalue の値を使って再レンダリングを発生させます。

③各画面でステート(データ)を参照したい時に使用するフック(useUserId)を作成する。

Providerはこうやって使用する

main.tsx
import { createRoot } from "react-dom/client";
import "./index.css";
import App from "./App";

import { BrowserRouter } from "react-router";
import { UserIdProvider } from "./contexts/UserIdContext";

createRoot(document.getElementById("root")!).render(
  <UserIdProvider>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </UserIdProvider>,
);
Sample.tsx
import { useUserId } from "../contexts/UserIdContext";


export const Sample = () => {
const { setUserId } = useUserId();
const { userId } = useUserId();

setUserId("testID");

return <>{userId}</>;
}

このようにアプリ全体を UserIdProvider で囲います。
useUserId(カスタムフック)を使用して取得した setUserIduserId を更新することによって⇩
UserIdProvider コンポーネント内の userId が更新され再レンダリングが発生します。
アプリ全体を UserIdProvider で囲っているため、囲っている配下のすべてのコンポーネントに再レンダリングが走り、ステートが更新されます。

全てのコンポーネントで最新のステートが反映されるため、どのコンポーネントでも最新のユーザーIDが参照できるという仕組みです。

まとめ

useContextは、単純にステートを更新する範囲を広げて、どのコンポーネントからでも参照できるようにするというもの。
propsで渡しているコンポーネントの範囲に抑えたいなどの、制約が無ければ useContext を使用すると便利だと思います。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?