我不知道这里使用哪种魔术,我想尽一切办法解决这个问题。
我想在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>
);
}
如果有人看到了什么,很可能错过了明显的事情。
谢谢!
答案 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
依赖于myData
和onHandleEvent
。我们现在没有引入这种依赖性,它已经具有这些依赖性,我们现在才更加清楚地看到它们。
还要注意,我们将在useEffect
更改时删除侦听器。如果每个渲染上的onHandleEvent
都发生变化,则可以在父组件中将useCallback
包裹起来。
答案 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]);
感谢阿格尼!