🙆
APIレスポンスを初期値としてステート管理したい
APIからのレスポンスをステートの初期値としたいケースはよくあるだろう。レスポンス結果を useEffect の依存配列にいれてステートにいれた経験がある(あまりよくないパターン)。
こういう場合は、useReducer
を利用するとよい。
コンポーネント内でReducer関数を直接定義し、そのコンポーネントのpropsや外部の状態(APIからのレスポンス)に基づいて状態管理を行うことができる。
const reducer = (data) => (state, action) => {
...
}
function App() {
const { data } = useQuery(key, queryFn)
const [state, dispatch] = React.useReducer(reducer(data))
}
APIレスポンスを useReducer の initialValue に渡せばいいのに、と考えるかもしれないが、reducerが最初に実行されるときはフェッチされる前なのでundefinedになってしまっている。
以下のようにカスタムフックとしてまとめると非常に見通しがよい。
const reducer = (amount) => (state, action) => {
switch (action) {
case 'increment':
return state + amount
case 'decrement':
return state - amount
}
}
const useCounterState = () => {
const { data } = useQuery({ queryKey: ['amount'], queryFn: fetchAmount })
return React.useReducer(reducer(data ?? 1), 0)
}
function App() {
const [count, dispatch] = useCounterState()
return (
<div>
Count: {count}
<button onClick={() => dispatch('increment')}>Increment</button>
<button onClick={() => dispatch('decrement')}>Decrement</button>
</div>
)
}
Discussion