fujjima blog
  • 経歴
  • 問い合わせ

setStateで古いstateを見てしまった

2020/12/28 17:41


基本的なところだけど、少し悩んでしまったのでメモ。

アプリのタイマー機能を実装しようとした際、setIntervalを使用しても時間が加算されない問題が発生した。 原因としては、setStateにオブジェクトを渡した場合、stateを即座にアップデートすることを保証しないというもの。

コンポーネントの state – React

今回のような、setIntervalでsetStateが呼ばれるなど参照したいstateが絶えず更新されているものである場合、「setStateに更新用の関数を渡し、その関数内の引数で最新のstateにアクセスして操作する」のが正しい実装内容となる。

駄目な例

下記の例だと、setStateにtimeに1を足した値を引数として渡しているが、この時にtimeが参照しているのは更新前のtimeである。 つまり、0秒から時間の加算が始まったとして、

// timeは親のコンポーネントからもらってくる数値
const [time, setTime] = useState(props.time || null);

useEffect(() => {
    const { taskId, recordingTaskId } = props;
    if (taskId && taskId === recordingTaskId) {
      // setIntervalで時間加算の関数(addSecond)を1秒毎に実行させる
      setTimerId(setInterval(addSecond, 1000));
    } else return;
  }, [props.recordingTaskId]);

  const addSecond = () => {
    // ここでsetStateに「time + 1」という値を渡してしまっているため、常に古いstateを見てしまっている
    setTime(time + 1);
  };

良い例

// timeは親のコンポーネントからもらってくる数値
const [time, setTime] = useState(props.time || null);

useEffect(() => {
    const { taskId, recordingTaskId } = props;
    if (taskId && taskId === recordingTaskId) {
      // setIntervalで時間加算の関数(addSecond)を1秒毎に実行させる
      setTimerId(setInterval(addSecond, 1000));
    } else return;
  }, [props.recordingTaskId]);

  const addSecond = () => {
    // 更新関数を渡しているため、この中のtは最新のstateが入っていることが保証されている
    setTime(t => t + 1);
  };

月別アーカイブ

  • ▶︎ ▼
    2025 (2)
    2025/01 (2)
  • ▶︎ ▼
    2024 (1)
    2024/01 (1)
  • ▶︎ ▼
    2023 (1)
    2023/05 (1)
  • ▶︎ ▼
    2022 (1)
    2022/10 (1)
  • ▶︎ ▼
    2021 (10)
    2021/11 (1)
    2021/09 (1)
    2021/08 (2)
    2021/05 (1)
    2021/03 (1)
    2021/02 (1)
    2021/01 (3)
  • ▶︎ ▼
    2020 (9)
    2020/12 (3)
    2020/11 (1)
    2020/07 (4)
    2020/01 (1)
  • ▶︎ ▼
    2019 (9)
    2019/12 (1)
    2019/10 (1)
    2019/08 (2)
    2019/07 (1)
    2019/06 (1)
    2019/05 (1)
    2019/02 (1)
    2019/01 (1)
  • ▶︎ ▼
    2018 (11)
    2018/11 (1)
    2018/10 (1)
    2018/09 (1)
    2018/08 (1)
    2018/06 (1)
    2018/05 (1)
    2018/04 (2)
    2018/02 (1)
    2018/01 (2)
  • ▶︎ ▼
    2017 (1)
    2017/12 (1)


  • タグ

    プログラミング
    読書
    備忘録
    chrome拡張
    gem
    rails
    フリーランス
    服
    その他