useImmer
useState と同様に,state と state を更新する関数のタプル型を返す hook。state を更新する関数は,immer の produce 関数か値を引数に取れる。
immer producer function
produce
関数は以下のような interface となる。
produce(baseState, recipe: (draftState) => void): nextState
baseState
を,recipe
関数によって変更した結果を返す。しかし,baseState は immutable。
import produce from "immer"; const baseState = [ { title: "Learn TypeScript", done: true, }, { title: "Try Immer", done: false, }, ]; const nextState = produce(baseState, (draftState) => { draftState.push({ title: "Tweet about it", done: false }); draftState[1].done = true; });
Managing state with immer producer function
import { useImmer } from "use-immer"; export default function App() { const [person, updatePerson] = useImmer({ name: "Michel", age: 33, }); function updateName(name: string) { updatePerson((draft) => { draft.name = name; }); } function becomeOlder() { updatePerson((draft) => { draft.age++; }); } return ( <div className="App"> <h1> Hello {person.name} ({person.age}) </h1> <input onChange={(e) => { updateName(e.target.value); }} value={person.name} /> <br /> <button onClick={becomeOlder}>Older</button> </div> ); }
updatePerson
にperson
state を更新する関数を渡すことで,state が更新される。
Managing state as simple useState hook
import { MouseEvent } from "react"; import { useImmer } from "use-immer"; export default function App() { const [age, setAge] = useImmer(20); function birthDay(event: MouseEvent<HTMLButtonElement>) { setAge(age + 1); } return ( <div> {age} <button onClick={birthDay}>It is my birthday</button> </div> ); }
useImmer の更新関数(setAge
)に値を渡すと,useState と同じ挙動となる。
useImmerReducer
useReducerと同じことができる。
import { useImmerReducer } from "use-immer"; type State = { count: number; }; const initialState: State = { count: 0 }; type Action = { type: "reset" | "increment" | "decrement" }; function reducer(draft: State, action: Action) { switch (action.type) { case "reset": return initialState; case "increment": return void draft.count++; case "decrement": return void draft.count--; } } export default function App() { const [state, dispatch] = useImmerReducer(reducer, initialState); return ( <> Count: {state.count} <button onClick={() => dispatch({ type: "reset" })}>Reset</button> <button onClick={() => dispatch({ type: "increment" })}>+</button> <button onClick={() => dispatch({ type: "decrement" })}>-</button> </> ); }