React Hook useCallback调用时未获取更新状态

时间:2020-07-29 01:17:42

标签: javascript reactjs socket.io react-hooks react-lifecycle-hooks

我正在开发此应用程序,在其中我双击页面并创建一个新项目。然后,我通知websockets服务器将此创建内容广播给所有其他正在听它的用户。在另一用户端,我必须添加此新项目,以便每个人都可以同步。

我正在使用react挂钩,这是我从头开始使用它的第一个应用程序。在此应用程序中,我遇到了类似的问题,但是我选择了此流程来说明基本问题。它必须涵盖大多数问题。

当我呼叫useCallback在“其他用户”侧添加项目时,items状态为旧(空)。因此,无论我创建项目多少次,页面上都只会显示我刚刚创建的项目。

这是代码示例:

import React, { useEffect, useState, useCallback } from 'react';
import io from 'socket.io-client';

let socket;

function App() {
  const [items, setItems] = useState({});

  const createItem = useCallback((data) => {
    const id = generateId();
    const newItem = { id, ...data };
    const newItems = { ...items, [id]: newItem };

    setItems(newItems)

    // When I create a new item, I notify the server to broadcast it
    socket.emit('itemCreated', newItem)
  }, [items, setItems])

  const doCreateItem = useCallback((item) => {
    // When someone else creates an item, it should be invoked be invoked
    const newItems = { ...items, [item.id]: item };
    setItems(newItems)
  }, [items]);

  useEffect(() => {
    // Connects to the server
    socket = io('ws://localhost:8090', {
      transports: ['websocket'],
      path: '/ws'
    });

    // Listens to event
    socket.on('createitem', (data) => {
      doCreateItem(data)
    });

    // I cannot add doCreateItem here, otherwise it will call this effect everytime doCreateItem is executed
  }, []);

  return (
    <div
      onDoubleClick={
        (e) => {
          createItem({});
        }
      }
    >

      {
        Object.values(items).map(item => {
          return (
            <div>{item.id}</div>
          )
        })
      }

    </div>
  );
}

export default App;

doCreateItem具有项依赖性。另一方面,useEffect依赖项列表不包含doCreateItem,主要是因为每次我从服务器收到新项目时,它都会重新调用useEffect回调。另外,因为我希望这种效果只能执行一次(在组件安装时)。我尝试将useEffect分成两部分,一个用于连接,另一个用于侦听器,但是还是一样。

我实际上有几个类似的问题。回调执行的次数超出了我的预期,或者该回调的状态未更新。

有人可以澄清我们应该如何解决这个问题?

谢谢!

修改

按照 @Ross 的建议,我更改了setItems调用以接收回调并返回新状态。这有助于setItems依赖性。但是我仍然无法在items函数中阅读doCreateItem。它总是空的。

我注意到的一件有趣的事是,如果我停止使用useCallback并在每个渲染器上重新创建函数,则该函数没有该状态的更新状态,但是它确实在该函数之外: / p>

function App() {
  const [items, setItems] = useState({});
 
  console.log('Rendered again and knows the state >', items)
  const doCreatePostIt = (data) => {
    console.log('Empty >', items)
    // ...
  };
  // ...
}

1 个答案:

答案 0 :(得分:1)

当下一个状态依赖于当前状态时,使用Storage Object Creator for bucket 'gs://my-test-bucket/spark-output-files/ Storage Object Viewer for bucket 'gs://my-test-bucket/spark-input-files/' 的{​​{3}}形式消除依赖项数组中的依赖项并解决“陈旧状态”问题。

  • useState钩子返回的setX函数是稳定的,在渲染之间不会改变(请参见functional update);从依赖项数组中删除是安全的
useState