未経験からエンジニア 奮闘記

未経験からエンジニアに自由に生きる途中

MENU

Next.jsでのsetStateの落とし穴:更新直後の値を正しく取得する方法

何をしたか?

Next.jsでsetStateを使う際に、ステートを更新した直後にその値を参照しようとすると、期待した値が取得できないという問題について書きました。この問題の原因と、どのように解決できるかを具体的なコード例を交えて紹介します。

背景

Reactでは、ステートの更新は非同期で行われるため、setStateを呼び出した直後にステートの値を参照しようとすると、まだ更新されていない古い値が返ってくることがあります。特にNext.jsでこの問題に直面することが多く、初心者や中級者の開発者が引っかかりやすいポイントです。

実装前のよくないコード & 何が問題なのか記載

コード例を見てみましょう。この例では、ステートの値を更新した直後にその値を使って何かをしようとしています。

import React, { useState } from 'react';

const Counter = () => {
  const [count, setCount] = useState(0);

  const incrementCount = () => {
    setCount(count + 1);
    alert(`Count is now: ${count}`); // ここでは更新された値が反映されません
  };

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={incrementCount}>Increment</button>
    </div>
  );
};

export default Counter;

挙動としてはこの様になります。setCountの後にcountを参照してalertを実行しても、0のままになっています。 これは、setStateが非同期であるため、setCountの呼び出し直後にcountを参照してもまだ更新されていないからです。

修正コード & 改善した内容

この問題を解決するには、useEffectフックを使ってステートの変更を監視し、更新後の値を使うようにします。

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

const Counter = () => {
  const [count, setCount] = useState(0);

  useEffect(() => {
    if (count > 0) {
      alert(`Count is now: ${count}`); // ステートが更新された後にアラートを表示
    }
  }, [count]);

  const incrementCount = () => {
    setCount(count + 1);
  };

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={incrementCount}>Increment</button>
    </div>
  );
};

export default Counter;

挙動を確認してみると、countの数が正しく反映さていますね

この修正コードでは、useEffectフックを使ってcountが更新された後にアラートを表示しています。 また、初期表示の際に処理が走るので、初期値の0の場合はalertを実行しない条件を追加しています。

まとめ

ReactやNext.jsでsetStateを使う際には、その非同期性を理解することが大切です。setStateを呼び出した直後にステートの値を参照しようとすると、期待した値が取得できないことがあります。この問題を回避するために、useEffectフックを使ってステートの変更を監視し、変更があった際に処理を行うようにしましょう。これで、ステートが更新された後の正しい値を取得できるようになります。