'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 };
{children}
↓
<MyvalueProvider>{children}</MyvalueProvider>
'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>
);
};
'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>
);
};
'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>
);
};
'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>
);
};
MyvalueProvider 以下のコンポーネントはコンテキストが変更されると全て最レンダリングされるので、以下のようにmemoしておきます。
export const Footer: FC = () => {
return (
<h1>Footer</h1>
);
};
↓
export const Footer: FC = memo(() => {
return (
<h1>Footer</h1>
);
});
Footer.displayName = 'Footer';