reactsetstateがループで正しく機能しない

Aug 31 2020

このような配列としてバックエンドから検証応答を取得しています

 [
        { param: "secondName", msg: "second name is required" },
        { param: "password", msg: "password is required" }
 ]

そして私はこのような反応コンポーネントに状態があります

  const [errs, setErrs] = useState({
    firstName: null,
    secondName: null,
    password: null,
    email: null,
  })

目標は、私の状態を変更するresponse.paramsことですnull。フォームに記載されているフィールドのみを送信し、残りはそのままにします。これは私が試したものです:

const submitFoo = () => {
    console.log(localErrs) //all props are set to null (default)
    res.forEach((single) => {
        setLocalErrs({
            ...localErrs,
            [single.param]: single.msg
        });
    });
    console.log(localErrs);//only password is set to the `response.msg`, instead of `password` AND `secondName`
};

しかし、問題は、「エラー状態」の最後の項目のみを変更していることです。出力は次のとおりです。

{
    first: null,
    second: null,
    password: 'password is required',
    email: null,
}

ps:配列をループし、Errs objの小道具をresponse.msgに直接設定することで、vanilla jsで試してみましたが、機能しました。したがって、問題はreactsetstateである必要があります

回答

3 AwaisRafiqChaudhry Aug 31 2020 at 00:25

次のように状態を設定するには、ファットアローアプローチを使用してみてください。

setLocalErrs(localErrs => ({ ...localErrs, [single.param]: single.msg }));

異なる非同期呼び出しなどにより、setter関数が同時に2回呼び出された場合の状態損失を回避します。

1 BhojendraRauniyar Aug 31 2020 at 00:34

ループ内で状態を更新することは避けてください。次のような状態を更新します。

let errObj = {}
res.forEach((single) => {
  errObj[single.param] = single.msg
})
setLocalErrs({
  ...localErrs,
  ...errObj
})

ちなみに、あなたは単に使用することができます:

setLocalErrs(errObj)

以来errObj、すべての状態値が更新されています。