为什么在循环内设置 useState 会执行不同的操作?

Why does setting useState inside a loop perform differently?

有人可以向我解释以下代码片段吗?为什么 handleClick() 不能正常工作(只设置了 newData 的 1 或 2 个数据属性)而 handleClick2() 可以正常工作。

我猜问题是循环引起的(因为这是唯一的区别),但为什么循环会导致这种效果?

沙盒link:https://codesandbox.io/s/restless-surf-u9i5s?file=/src/App.js:0-969

import React, { useState, useEffect } from "react";
import "./styles.css";


const App = () => {
  const [newData, setNewData] = useState({
    data1: '',
    data2: '',
    data3: '',
    data4: ''
  })

  const handleClick = () => {
    let fields = ['data1', 'data2', 'data3', 'data4']
    let field
    for (field of fields) {
        setNewData(oldState => ({...oldState, [field]: 'test'}))
    }
  }

  const handleClick2 = () => {
    setNewData(oldState => ({...oldState, data1: 'test'}))
    setNewData(oldState => ({...oldState, data2: 'test'}))
    setNewData(oldState => ({...oldState, data3: 'test'}))
    setNewData(oldState => ({...oldState, data4: 'test'}))
  }

  useEffect(() => {
    console.log('State: ' + JSON.stringify(newData))
  }, [newData])

  return (
    <div className="App">
      <button onClick={handleClick}>Click</button>
      <button onClick={handleClick2}>Click2</button>
    </div>
  );
}

export default App

原因是:

setNewData 是异步函数。当你调用 setNewData 时,React 会以某种方式将其回调函数推送到事件循环中,然后在主线程为空时在主线程中回调它。当 setNewData 回调函数在 main 中调用时 fieldtest4 因为 for (field of fields) 同步函数。 ==> 只有 setNewData(oldState => ({...oldState, data4: 'test'})) 调用了 4 次。

您可以在 setNewData 回调函数中记录 field 并查看它的值。

for (field of fields) {
  console.log(field)
  setNewData(oldState => {
    console.log(field)
    return { ...oldState, [field]: "test" }
  })
}

Codesandbox for it