React 钩子 useState 没有正确更新

问题描述

我有一个关于 react + mobx + hooks API 没有正确更新状态的奇怪问题

这是下面示例的控制台输出。没关系 findDomNode 错误,与 toast 组件库过时有关

enter image description here

假设有一个服务列表和一组相应的 id。这是一个管理面板,我想在其中添加删除服务器端的当前服务。我将选定的服务(即复选框)存储在 useState 中。也可以从后端删除服务,因此我需要使用后端响应中的内容更新前端的选定(复选框)列表

问题是显示更新就在 useEffect 内部的钩子,但在渲染函数 (handleListColCallback) 内部 selected 的值没有更新,始终保留已删除的值

尝试了useMemouseCallback等的多种组合,结果总是一样。我做错了什么吗?

const AdminServices = observer(() => {
  const [selected,setSelected] = useState([]);

  const serviceContext = useContext(ServiceStoreContext);

  const handleListColCallback = async (params) => {
    if (params.type === 'select-checkBox') {
      // STEP 3 - I want to manipulate with state removing or adding checked id to array 
      // ERROR here - selected state still showing old value (not the same as in useEffect)
      console.log('checkBox select',selected);

    } else if (params.type === 'delete-from-node') {
      // STEP 1 - I call delete action,it runs successfully
      await serviceContext
        .deleteFromNode({ service_id: params.id })
    }
  };

  useEffect(() => {
    // STEP 2 - when mobx store updates,I want to reset component state with new values
    setSelected(serviceContext.nodeListArrayIds);
  },[serviceContext.nodeListArrayIds]);

  useEffect(() => {
    // selected shows current values (this effect is just for testing)
    console.log('selected updated',selected);
  },[selected]);
}

更新

问题已通过使用以下 setState 和 handleListColCallback 更新解决。如果有人能解释为什么纯 setStatesetState((curState) => ... )

不同,我会很高兴
  useEffect(() => {
    setSelected(() => {
      return [...serviceContext.nodeListArrayIds];
    });
  },[serviceContext.nodeListArrayIds]);

    } else if (params.type === 'select-checkBox') {
      setSelected((selected) => {
        const index = selected.indexOf(params.id);

        if (index === -1) {
          return [...selected,...[params.id]];
        } else {
          return selected.filter((x) => x !== params.id);
        }
      });

解决方法

上下文中的数组 (serviceContext.nodeListArrayIds) 似乎以某种方式重新添加了已删除的项目(OP 可能想要调查的内容)。

setSelected(serviceContext.nodeListArrayIds);setSelected([...serviceContext.nodeListArrayIds]); 之间的区别在于,在第一种情况下,selected 是对 serviceContext.nodeListArrayIds 的引用,因此将反映对它的任何更改。 [...serviceContext.nodeListArrayIds] 创建一个浅层克隆(类似于 .slice()),因此对 serviceContext.nodeListArrayIds 的更改不会影响它。