フロントエンド開発といえば。
react アプリの初期化( npm init vite@latest <アプリ名> )

React hooksの概要 useContext による Provider

1. Providerコンポーネント /src/providers/MyValueProvider.tsx

'use client';

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

type Myvalue = 'ja' | 'en';

const initialValue = 'ja';

// 値を保持するコンテキスト
export const MyvalueContext = createContext<Myvalue>(initialValue);

// 値を更新する関数を提供するコンテキスト
const MyvalueDispatcherContext = createContext<
  Dispatch<SetStateAction<Myvalue>> | undefined
>(undefined);

interface MyvalueProviderProps {
  children: ReactNode;
}

const MyvalueProvider: React.FC<MyvalueProviderProps> = ({ children }) => {
  const [myvalue, setMyvalue] = useState<Myvalue>(initialValue);

  return (
    <MyvalueContext.Provider value={myvalue}>
      <MyvalueDispatcherContext.Provider value={setMyvalue}>
        {children}
      </MyvalueDispatcherContext.Provider>
    </MyvalueContext.Provider>
  );
};

// 値のカスタムフック
const useMyvalue = () => useContext(MyvalueContext);

// 値を更新する関数用のカスタムフック
const useMyvalueDispatcher = () => {
  const context = useContext(MyvalueDispatcherContext);
  if (context === undefined) {
    throw new Error(
      'useMyvalueDispatcher must be used within a MyvalueProvider'
    );
  }
  return context;
};

export { MyvalueProvider, useMyvalue, useMyvalueDispatcher };

2. 上位層のコンポーネント(reactなら App.tsx など)(next.js なら /app/page.tsx や /app/layout.tsx など)

{children}

  ↓

<MyvalueProvider>{children}</MyvalueProvider>

3. コンテキストを受け取るコンポーネント ( src/app/ClientCommponent.tsx )

'use client';

import { FC } from 'react';
import { MyvalueSub1 } from './MyvalueSub1';
import { MyvalueSub2 } from './MyvalueSub2';
import { MyvalueButton } from './MyvalueButton';

export const ClientCommponent: FC = () => {
  return (
    <div>
      <h1>ClientCommponent</h1>
      <MyvalueButton />
      <MyvalueSub1 />
      <MyvalueSub2 />
    </div>
  );
};

4. コンテキストの値を表示するコンポーネント ( src/app/MyvalueSub1.tsx )

'use client';

import { FC } from 'react';
import { MyvalueContext } from '@/providers/MyvalueProvider';

export const MyvalueSub1: FC = () => {
  return (
    <div style={{ border: '10px solid red', padding: '10px', margin: '10px' }}>
      <h1>MyvalueSub1</h1>
      <MyvalueContext.Consumer>
        {(value) => {
          return <div>{value}</div>;
        }}
      </MyvalueContext.Consumer>
    </div>
  );
};

5. コンテキストの値を表示するコンポーネント ( src/app/MyvalueSub2.tsx )

'use client';

import { FC, useContext } from 'react';
import { MyvalueContext } from '@/providers/MyvalueProvider';

export const MyvalueSub2: FC = () => {
  const value = useContext(MyvalueContext);

  return (
    <div
      style={{ border: '10px solid orange', padding: '10px', margin: '10px' }}
    >
      <h1>MyvalueSub2</h1>
      <div>{value}</div>
    </div>
  );
};

6. コンテキストの値更新するボタンコンポーネント ( src/app/MyvalueButton.tsx )

'use client';

import { useMyvalueDispatcher } from '@/providers/MyvalueProvider';
import { FC } from 'react';

export const MyvalueButton: FC = () => {
  const setMyvalue = useMyvalueDispatcher();
  const handleClick = () => {
    setMyvalue(new Date().toLocaleString('ja-JP', { timeZone: 'Asia/Tokyo' }));
  };
  return (
    <button
      style={{ background: 'lightgray', padding: '10px', margin: '10px' }}
      onClick={handleClick}
    >
      MyvalueButton
    </button>
  );
};

6. プロバイダで囲まれたコンポーネントは全て最レンダリングがかかるので memo化しましょう

MyvalueProvider 以下のコンポーネントはコンテキストが変更されると全て最レンダリングされるので、以下のようにmemoしておきます。

export const Footer: FC = () => {
  return (
      <h1>Footer</h1>
  );
};

  ↓

export const Footer: FC = memo(() => {
  return (
      <h1>Footer</h1>
  );
});
Footer.displayName = 'Footer';
No.2473
03/29 08:59

edit