🍃
TypeScript+useContext+useReducerで簡易な状態管理を実装する
概要
- TypeScript環境でuseContext+useReducerを用いて簡易な状態管理をするための最低限の書き方
- 記述量が割と多く、毎回思い出しながら書いていているとモタつくので、自分のために記録
- あまり熟練者ではないので、おかしな箇所やもっとこうした方が良いなどあれば、教えてくださいm(_ _)m
内容
- 新規メニューを追加するまでのユーザーの入力値を保持するステート
- (何のメニューだよ、って感じですが、特に「メニュー」という状態の特性は意識しなくて大丈夫です)
- 状態管理のための最低限の内容だけ記載してます
store/newMenu/index.ts
- createContextで状態管理用の枠を作成
- useReducerでstateと変更用関数をカスタムフックで定義
import React from 'react';
import { NewMenuActionType, NewMenuState, NewMenuStateWithAction } from './newMenuType';
import reducer from './reducer';
type UseNewMenuStateType = () => {
newMenuState: NewMenuState
dispatchNewMenuState: React.Dispatch<NewMenuActionType>
}
const initialState: NewMenuState = {
title: '',
// その他もろもろ
};
export const NewMenuContext = React.createContext<NewMenuStateWithAction>(
{ newMenuState: initialState, dispatchNewMenuState: () => {} },
);
export const useNewMenuState: UseNewMenuStateType = () => {
const [newMenuState, dispatchNewMenuState] = React.useReducer(reducer, initialState);
return { newMenuState, dispatchNewMenuState };
};
store/newMenu/reducer.ts
- 変更用関数の中身を定義
import { Reducer } from 'react';
import { NewMenuState, NewMenuActionType } from '@store/newMenu/newMenuType';
const reducer: Reducer<NewMenuState, NewMenuActionType> = (
oldState, action,
) => {
switch (action.type) {
case 'changeTitle': return { ...oldState, title: '変更後のタイトル' };
default: return oldState;
}
};
export default reducer;
store/newMenu/newMenuType.ts
- ここで型を定義
import { Dispatch } from 'react';
export interface NewMenuState {
title: string
}
export type NewMenuActionType =
| { type: 'changeTitle' }
export type NewMenuStateWithAction = {
newMenuState : NewMenuState
dispatchNewMenuState: Dispatch<NewMenuActionType>
}
components/NewMenu.tsx
- メニューstateをもつ最上部の親を設定
- ここまでの4ファイルで事前準備完了
import React from 'react';
import { NewMenuContext ,useNewMenuState } from '@store/newMenu';
export default () => {
const newMenuState = useNewMenuState();
return (
<NewMenuContext.Provider value={newMenuState}>
<SomeComponent />
</NewMenuContext.Provider>
);
};
conponents/SomeConponent.tsx
- 実際に値を使ったり変更したりの例
import React from 'react';
import { NewMenuContext } from '@store/newMenu';
export default () => {
const { newMenuState, dispatchNewMenuState } = React.useContext(NewMenuContext);
return (
<>
<p>{newMenuState.title}</p>
<button
onClick={() => dispatchNewMenuState({ type: 'changeTitle' })}
/>
</>
)
}
以上です。関係ないですが、Recoilに期待しています。
Discussion