React Context を用いた簡易 Store
課題
- redux を引っ張り出すと大仰になる。Context 下に共有ステートを持ってそこに setState できるだけでよい。
- なので、次の 2 つを用意する
- 現在の state を参照する
const appState = useAppState()
- 現在の state を更新する関数を返す
const setAppState = useSetAppState()
- 現在の state を参照する
React.useState()
と違って分割している理由は、主にパフォーマンス上の理由- 大域な参照なので、可能な限りステートを参照したくない
setState()
の API は(prevState: State) => State
も取れるので、状態更新用途に限ってはそもそもuseAppState()
せずに済むことが多い
- でも毎回書いてるけどボイラープレート感強い上に忘れるのでここにメモする
毎回書いてるボイラープレート
// src/contexts/AppStateContext.tsx
import React, { Dispatch, SetStateAction, useContext, useState } from "react";
export type AppState = {
value: number;
};
const initialState: AppState = {
value: 0,
};
const AppStateContext = React.createContext<AppState>(initialState);
const SetAppStateContext = React.createContext<
Dispatch<SetStateAction<AppState>>
>(() => {});
export function useAppState() {
return useContext(AppStateContext);
}
export function useSetAppState() {
return useContext(SetAppStateContext);
}
export function AppStateProvider(props: {
initialState?: AppState;
children: React.ReactNode;
}) {
const [state, setState] = useState<AppState>(
props.initialState ?? initialState
);
return (
<AppStateContext.Provider value={state}>
<SetAppStateContext.Provider value={setState}>
{props.children}
</SetAppStateContext.Provider>
</AppStateContext.Provider>
);
}
使い方
import React from "react";
import ReactDOM from "react-dom";
import {
AppStateProvider,
useAppState,
useSetAppState,
} from "./contexts/AppStateContext";
function Counter() {
const state = useAppState();
const setAppState = useSetAppState();
return (
<div>
{state.value}
<button
onClick={() => {
setAppState((s) => ({ value: s.value + 1 }));
}}
>
++
</button>
</div>
);
}
function App() {
return (
<AppStateProvider>
<Counter />
</AppStateProvider>
);
}
ReactDOM.render(<App />, document.querySelector("#root"));
History
6818a86 - Update Sat Jun 6 19:41:40 2020 +0900
fc5b53c - Update Wed May 27 16:19:07 2020 +0900