@keitafujimoto0917

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

Reactプロジェクトで状態更新後の値がすぐに反映されず、古いデータが使われてしまう問題

現在、Reactで業務用Webアプリケーションを開発しています。

開発中に、stateを更新した直後にその値を参照すると、更新前の古い値が取得されてしまい、予期しない動作になる問題に遭遇しました。

Reactのstate更新は非同期であることは知っていましたが、実際の開発では思った以上に影響が大きく、かなり悩まされました。

発生した問題

ユーザーがボタンをクリックすると、カウントを増やした後に最新の値をAPIへ送信したいと考えていました。

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

const handleClick = () => {
setCount(count + 1);

console.log(count);

sendToApi(count);
};

しかし、期待していた動作は

1
2
3
...

なのに、実際には

0
1
2
...

のように、1つ前の値が送信されてしまいます。

その結果、バックエンド側に誤ったデータが保存されることがありました。

試したこと

まず、以下のように変更してみました。

setCount(count + 1);

setTimeout(() => {
sendToApi(count);
}, 0);

しかし、これでも状況によっては古い値が送信されてしまい、根本的な解決にはなりませんでした。

現在の対応

一旦、以下のように新しい値を変数に保持してから利用しています。

const handleClick = () => {
const nextCount = count + 1;

setCount(nextCount);

sendToApi(nextCount);
};

また、以下のように useEffect を利用して処理する方法も検討しています。

useEffect(() => {
sendToApi(count);
}, [count]);
質問

Reactではstate更新直後に最新の値を利用したい場合、一般的にはどのような実装が推奨されるのでしょうか?

また、

一時変数を利用する方法
useEffect を利用する方法
useRef を利用する方法

などがありますが、実務ではどの方法が最もよく採用されているのでしょうか。

同じような問題を経験された方がいらっしゃいましたら、ベストプラクティスを教えていただけると嬉しいです。

0 likes

2Answer

なんで他の方の質問に文章生成ai?を使って回答してるんですか、、、

0Like

非同期なので、いつ更新されるかわからないのが怖いところですね。
書かれている対処では、一見うまく行きますが、
クリックの連打をすると変な値になります。

prev を使って、前の値に+1するのが安全です。

const handleClick = () => {
  setCount(prev => prev + 1);
};

useEffect(() => {
  if (count === 0) return;
  sendToApi(count);
}, [count]);

ただし、この場合は連打したら途中が抜けます。(最終カウント数は正しい)

クリック全てに処理がほしいのなら、素直にref使うほうがいいかも

const countRef = useRef(0);
const handleClick = () => {
  countRef.current += 1;
  sendToApi(countRef.current);
};
0Like

Your answer might help someone💌