MeWrite Docs

React state not updating

ReactでuseStateの値が更新されない場合の原因と解決方法

概要

Reactで useState の値が期待通りに更新されない問題は、非同期処理の理解不足や参照の問題が主な原因です。

問題のパターン

1. 同一レンダリング内での複数更新

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// NG: stateは即座に更新されない
function Counter() {
  const [count, setCount] = useState(0);

  const handleClick = () => {
    setCount(count + 1);
    setCount(count + 1);
    setCount(count + 1);
    // 結果: 1 (3ではない)
  };
}

解決策: 関数形式を使用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
function Counter() {
  const [count, setCount] = useState(0);

  const handleClick = () => {
    setCount(prev => prev + 1);
    setCount(prev => prev + 1);
    setCount(prev => prev + 1);
    // 結果: 3
  };
}

2. オブジェクト/配列の参照問題

1
2
3
4
5
6
7
8
9
// NG: 同じ参照を変更しても再レンダリングされない
function UserList() {
  const [users, setUsers] = useState([]);

  const addUser = () => {
    users.push({ name: 'John' }); // 直接変更
    setUsers(users); // 同じ参照
  };
}

解決策: 新しい参照を作成

1
2
3
4
5
6
7
8
9
function UserList() {
  const [users, setUsers] = useState([]);

  const addUser = () => {
    setUsers([...users, { name: 'John' }]);
    // または
    setUsers(prev => [...prev, { name: 'John' }]);
  };
}

3. ネストされたオブジェクトの更新

1
2
3
4
5
6
7
// NG
const [user, setUser] = useState({ name: 'John', address: { city: 'Tokyo' } });

const updateCity = () => {
  user.address.city = 'Osaka'; // 直接変更
  setUser(user);
};

解決策: イミュータブルに更新

1
2
3
4
5
6
7
8
9
const updateCity = () => {
  setUser(prev => ({
    ...prev,
    address: {
      ...prev.address,
      city: 'Osaka'
    }
  }));
};

4. 非同期処理内での古い値

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// NG: クロージャが古い値を参照
function Timer() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    const interval = setInterval(() => {
      setCount(count + 1); // 常に0 + 1 = 1
    }, 1000);
    return () => clearInterval(interval);
  }, []); // 依存配列が空
}

解決策: 関数形式を使用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
function Timer() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    const interval = setInterval(() => {
      setCount(prev => prev + 1);
    }, 1000);
    return () => clearInterval(interval);
  }, []);
}

5. useEffectの依存配列の問題

1
2
3
4
// NG: countが依存配列にない
useEffect(() => {
  console.log(count); // 常に初期値
}, []); // 空の依存配列

解決策: 依存関係を追加

1
2
3
useEffect(() => {
  console.log(count);
}, [count]); // countを依存配列に追加

6. イベントハンドラ内での即時参照

1
2
3
4
5
// NG: 更新後の値をすぐに使おうとしている
const handleSubmit = () => {
  setFormData({ ...formData, submitted: true });
  console.log(formData.submitted); // まだfalse
};

解決策: useEffectで監視

1
2
3
4
5
6
7
8
9
const handleSubmit = () => {
  setFormData(prev => ({ ...prev, submitted: true }));
};

useEffect(() => {
  if (formData.submitted) {
    console.log('Submitted!');
  }
}, [formData.submitted]);

デバッグ方法

1
2
3
4
5
// React DevToolsを使用
// または
useEffect(() => {
  console.log('state updated:', state);
}, [state]);

関連エラー

関連エラー

React の他のエラー

最終更新: 2025-12-17