かもメモ

自分の落ちた落とし穴に何度も落ちる人のメモ帳

React TypeScript 1回だけ更新する state に useReducer を使う

レンダリング後に useEffect で何かしらの初期化処理を行って、完了したことを明示したい時など 1回だけ更新する state を作りたいケース
別に useState でも良いのだけれど、useState は setter が返されるので state を自由に更新できてしまうので、state の値を reducer 関数でコントロールできる useReducer を使うパターン

useReducer()

const [state, dispatch] = useReducer(reducer, initialArg, init?);

cf. useReducer – React

useReducer は state を更新する reducer 関数と state の初期値 initialArg を取って、state と reducer を呼び出す為の dispatch を返す
📝: init? は初期 state を返す初期化関数。指定されている場合は初期値が init(initialArg) の結果となる

reducer 関数

const reducer = (currentState, value) => newState;

reducer 関数は、現在の state と dispatch に渡される値 (value) を引数にとり、新しい state の値を返す関数であれば良い

useReducer() で 1回だけ更新される state を作る

1回だけ更新される state を作成するには reducer が常に同じ値を返せば良い

import { useEffect, useState, useReducer } from 'react';

const useLocalStorage = () => {
  const [isPending, complete] = useReducer(() => false, true);
  const [value, setValue] = useState<LodacStorageData | undefined>(undefined);
  useEffect(() => {
    complete();
    const data = localStorage.getItem(LOCALSTORAGE_KEY);
    // localStorage に値が存在しない場合
    if (data === null) {
      return;
    }
    try {
      const v = JSON.parse(data) as LodacStorageData;
      setValue(v);
    } catch {
      localStorage.removeItem(LOCALSTORAGE_KEY);
    }
  }, []);
  
  return {isPending, storageData: value};
}

useReducer() を使って toggle になる state を実装する

reducer 関数には現在の state が渡されることを利用すると toggle になる state が簡単に作れる

import { useReducer } from "react";

export const useToggle = (initialValue: boolean = true) => {
  const [toggleState, onToggle] = useReducer((state) => !state, initialValue);

  return {
    toggleState,
    onToggle,
  };
};

const App = () => {
  const { toggleState, onToggle } = useToggle();

  return <button onClick={onToggle}>{toggleState ? 'ON' : 'OFF'}</button>
}

Sample

useReucer() 使う方法毎回ググってたのでメモ

プライムセールでは モバイルモニター (VisionOwl 14インチ) 買いました!


[参考]

今期は 逃げ上手の若君 を観ておけばよいですか?