ReactJS 16.13.1在侦听器中挂钩非一致状态

时间:2020-04-09 13:50:08

标签: reactjs react-hooks

我不知道这里使用哪种魔术,我想尽一切办法解决这个问题。

我想在websocket侦听器中使用处于组件反应状态的数组,当触发侦听器时,我的状态是一个空数组,但是我在useEffect中设置了一个值。

这是我的代码:

function MyComponent() {
    const [myData, setMyData] = useState([]);
    const [sortedData, setSortedData] = useState([]);

    useEffect(() => {
        someAxiosCallWrapped((response) => {
            const infos = response.data;
            setMyData(infos.data);
            const socket = getSocket(info.socketNamespace); // wrap in socket namespace
            handleEvents(socket);
        });
    }, []);


    useEffect(() => {
        setSortedData(sortTheArray(myData));
    }, [myData]);

    const handleEvents = (socket) => {
        socket.on('EVENT_NAME', handleThisEvent);
    };

    const handleThisEvent = payload => {
        const myDataCloned = [...myData]; //<=== my probleme is here, whatever I've tried myData is always an empty array, I don't understand why
        /**
         * onHandleEvent is an external function, just push one new object in the array no problem in the function
         */
        onHandleEvent(myDataCloned, payload);
        setMyData(myDataCloned);
    };

    return (
        <div>
            // display sortedData no problem here
        </div>
    );
}

如果有人看到了什么,很可能错过了明显的事情。

谢谢!

3 个答案:

答案 0 :(得分:2)

来自docs

组件中的任何函数(包括事件处理程序和效果)都可以从其创建的渲染中“看到”道具和状态。

在安装时从handleEvents调用useEffect,因此它只能看到初始数据([])。为了更好地捕获此错误,我们可以将函数移到useEffect内(除非在外部绝对必要)

useEffect(() => {
  const handleEvents = (socket) => {
    socket.on('EVENT_NAME', handleThisEvent);
  };

  const handleThisEvent = payload => {
      const myDataCloned = [...myData];
      onHandleEvent(myDataCloned, payload);
  };

  someAxiosCallWrapped((response) => {
    const infos = response.data;
    setMyData(infos.data);
    const socket = getSocket(info.socketNamespace); // wrap in socket namespace
    handleEvents(socket);
  });

  return () => {
    socket.off('EVENT_NAME', handleThisEvent);
  }
}, [myData, onHandleEvent]);

现在,您可以看到useEffect依赖于myDataonHandleEvent。我们现在没有引入这种依赖性,它已经具有这些依赖性,我们现在才更加清楚地看到它们。

还要注意,我们将在useEffect更改时删除侦听器。如果每个渲染上的onHandleEvent都发生变化,则可以在父组件中将useCallback包裹起来。

Is it safe to omit a function from dependencies - Docs

答案 1 :(得分:0)

一旦数组值更改,您需要使用useMemo挂钩来更新函数,除非挂钩组件始终使用初始状态值。 将问题部分更改为此并尝试

const handleThisEvent = useMemo(payload => {
       const myDataCloned = [...myData]; 
       onHandleEvent(myDataCloned, payload);
       setMyData(myDataCloned);
   },[the values you need to look for(In this case myData)]);

答案 2 :(得分:0)

我最终想出了这样的代码。

useEffect(() => {
  let socket;
  someAxiosCallWrapped((response) => {
    const infos = response.data;
    setMyData(infos.data);
    socket = getSocket(info.socketNamespace); // wrap in socket namespace
    setSocket(socket)

  });

  return () => {
    if(socket) {
        socket.disconnect();
    }
  }
}, []);

useEffect(() => {
    if(socket) {
        const handleEvents = (socket) => {
        socket.off('EVENT_NAME').on('EVENT_NAME', handleThisEvent);
      };

      const handleThisEvent = payload => {
          const myDataCloned = [...myData];
          onHandleEvent(myDataCloned, payload);
      };
    }
}, [socket, myData, onHandleEvent]);

感谢阿格尼!