I am having trouble getting my head around state management in React.
I'm tempted to say its rubbish but I know in truth I'm just not understanding some fundamental thing. I've set up a simple example on Plunker that basically illustrates what I'm trying to do

const Hello = ()=>{
  const [myArr, setMyArr] = useState([]);

  const addToArr = ()=>{
    setMyArr(arr => arr.concat(arr.length+1));
  }

  const clearArr = ()=>{
    setMyArr(arr => [])
  }

  useEffect(()=>{
    console.log(myArr);
  }, [myArr]);

  return <div>
    <button onClick={addToArr}>Add</button>
    <button onClick={clearArr}>Clear</button>
    <button onClick={()=>{
      clearArr();
      addToArr();
    }}>Clear Then Add</button>
  </div>
}
export default Hello;

Run the preview and you'll see three buttons. With the dev tools console open click the buttons.
Add and Clear work as expected and result in an array with 1 additional item or an empty array.
Clear Then Add is where I am confused. The final outcome is correct, an array with 1 item, but I would expect to see an empty array logged first.

I've read a bunch of stuff about how state updates are async and React is trying to minimise rerenders and what-have-you but in my instance I need to respond to that empty array.
I have a few components that watch the list and some of then need to know if updates are taking the form of items being added to an existing list or items being added after the list was cleared.
I've also read that you should not call methods of child components in React.

那么,有没有办法对第一次清理名单做出回应?

另外,我不明白的基本概念可能是什么,因为在我看来,如果你无法知道它们何时完成或无法倾听它们何时发生,拥有异步状态更新似乎是一件非常令人头疼的事情. 再说一次,我确信我的 struct 才是问题所在,但这真的让我很恼火,我需要咆哮.

推荐答案

在react 16中,应该是这样的情况:多个排队的状态更新将被批处理unless,它们被异步触发.请看这个answer来解释.

示例:

<button
  onClick={() => {
    Promise.resolve().then(() => {
      clearArr();
      addToArr();
    });
  }}
>
  Clear Then Add
</button>

Reaction更新是异步处理的,但它们是102 async,这意味着状态更新器函数不是async,不能等待.这意味着您不能将状态更新排队,然后等待它,并期望在相同的回调作用域中读取更新后的状态值.

如果您想要/需要对中间的"清除状态"做出react ,下面的说明似乎可以在" destruct "批处理机制时起作用.

<button
  onClick={async () => {
    await clearArr();
    addToArr();
  }}
>
  Clear Then Add
</button>

上面的做法当然很奇怪,从历史上看是行不通的,但处理状态更新的方式一直是内部实现的细节,可能会发生变化.

如果上面的代码让您像我一样不寒而栗,那么下面是一种稍微更传统的方法来分解排队的更新.它使用setTimeout调用将第二个状态更新放在Java事件队列的末尾.

<button
  onClick={() => {
    clearArr();
    setTimeout(addToArr, 0);
  }}
>
  Clear Then Add
</button>

演示

演示了如何使用这两种实现来中断排队状态更新的批处理.

Edit how-to-respond-to-rapid-sequential-state-updates-with-usestate

[]            // initial
(1) [1]       // add
(2) [1, 2]    // add
(3) [1, 2, 3] // add
[]            // clear then add -> clean
(1) [1]       // clear then add -> add

Reactjs相关问答推荐

TypeError:SearchProduct.get()获得了意外的关键字参数查询'

React,React Router,Joy UI:如何在导航离开和返回后禁用snackbar重新出现?

如何通过回调函数获取多个值?

无法将react 路由状态从路由传递给子组件

自定义变量默认、聚焦和填充时所需TextField中标签的星号 colored颜色

在React中使用映射创建flex组件

滚动视图样式高度没有任何区别

useEffect 和 ReactStrictMode

MERN,将动态列表中的元素插入数组

我无法通过 useContext 显示值

React中的功能性组件克隆优化

无法从子组件传递数据到父组件

如何使用 redux 和 react-plotly.js

如何初始化 redux 全局存储 preloadedState

如何将我的 ID 值传递给下一个组件?

ReactJs 行和列

在react 路由dom版本6中的组件内添加路由

React useEffect hooks return () => cleanup() vs return cleanup

在状态中存储多个选定的选项

Select MenuItem 时 Material-ui 不更改样式