0
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?

next.jsでReactのContextを利用する時の心得

Posted at

複数ページ間にデータを共有した時や、深いコンポーネント階層構造のpropsバケツリレイ問題を解消したい時とか、ReactのContextを利用する手段がある。基本グローバルだが、Providerの括る範囲により局所に制限されることができる。

この記事ではnext.jsでReactのContextを利用する時の心得をメモする。

サンプルのソースコード

早速ソースコードを記載して、心得は全てのこれをベースにしている。

'use client';

import {
  createContext,
  useState,
  useContext,
  type ReactNode,
  type Dispatch,
  type SetStateAction,
} from 'react';

export type Hoge = {
  id?: number;
  name: string;
  values: string[];
};

const HogeContext = createContext<Hoge | undefined>(undefined);
const HogeUpdateContext = createContext<Dispatch<SetStateAction<Hoge>> | undefined>(undefined);

type Props = {
  children: ReactNode;
};

export function HogeProvider({ children }: Props) {
  const [searchCondition, setHoge] = useState<Hoge>({
    id: undefined,
    name: '',
    values: [],
  });

  return (
    <HogeContext.Provider value={searchCondition}>
      <HogeUpdateContext.Provider value={setHoge}>{children}</HogeUpdateContext.Provider>
    </HogeContext.Provider>
  );
}

export const useHoge = () => {
  const context = useContext(HogeContext);
  if (context === undefined) {
    throw new Error('useHoge must be used within a HogeProvider');
  }
  return context;
};

export const useHogeUpdate = () => {
  const context = useContext(HogeUpdateContext);
  if (context === undefined) {
    throw new Error('useHogeUpdate must be used within a HogeProvider');
  }
  return context;
};

心得1:Context利用のため、next.jsの'use client';をContextのソースコードファイルに記載する

next.jsのapp routerを利用する場合、RCC(React Client Component)しかContextを利用できない。RSC(React Server Component)からContextのProviderを利用する可能性があるので、Context定義ファイルに'use client';を付けた方が無難。

心得2:valueとvalueを更新する関数は別々のContextにする

このアンチパターン記事に書いた通り、{hoge, setHoge}オブジェクトを1つのContextに纏める場合、片方が変わったら、新たのオブジェクトが生成されるため、hogeとsetHogeの利用されるところが全て再描画されてしまう。

setHogeが基本不変なものであり、hogeと別のContextに設定する場合は、お互いに影響せず、パフォーマンスの悪い影響が避けられる。

  return (
    <HogeContext.Provider value={searchCondition}>
      <HogeUpdateContext.Provider value={setHoge}>{children}</HogeUpdateContext.Provider>
    </HogeContext.Provider>
  );

心得3:繋ぎ込みも同じファイルにする

  • ProviderとContext定義を1つのファイルの中に纏める
  • Context自体を公開せず、代わりにContext値を取得するHooksを定義する

心得4:初期値をundefinedにして、Hooks中にundefinedチェックを行なう

HogeProviderで括るコンポーネント中からしかuseHogeやuseHogeUpdateを利用できないが、実装時に忘れていた場合、ちゃんとErrorを出すようにして、正しい使い方を保証する。

export const useHoge = () => {
  const context = useContext(HogeContext);
  if (context === undefined) {
    throw new Error('useHoge must be used within a HogeProvider');
  }
  return context;
};

export const useHogeUpdate = () => {
  const context = useContext(HogeUpdateContext);
  if (context === undefined) {
    throw new Error('useHogeUpdate must be used within a HogeProvider');
  }
  return context;
};

心得5:stateとreducerの使い分け

  • 上記サンプルソースコードのような単純な丸ごとのデータ更新の場合はstateを利用する
  • データに対して追加、削除、更新みたい色んな操作がある場合はreducerを利用する

参考記事

0
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
0
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?