如何防止由于异步代码和 websocket 竞争条件导致的反应状态覆盖?
How to prevent react state overwrites due to asynchronous code and websocket race condition?
我正在构建一个使用 recoiljs 作为我的状态管理器的 React 应用程序,我需要从网络套接字获取数据并相应地更新状态。我不使用常规数组的原因是我需要在我的组件之间共享状态。
详细地说,该组件有一个 WebSocket 连接,并且将有数据流入其中。然后它需要通过推送接收到的数据来更新数组。问题是由于组件生命周期或其他原因,状态写入错误,这就是我认为发生的事情
- 收到响应 1 并调用 setState([...state, data])
- 然后收到响应 2 并调用 setState([...state, data])
- 状态实际上是由Response 1设置的
- 状态由响应 2 设置
问题是当响应 2 进入并调用 setState 时,它有一个旧版本的状态,不包括响应 1。
我似乎不知道如何解决这个问题。这是精简代码。
import {atom} from "recoil"
import {useRecoilState} from "recoil"
const WebSocket = require("isomorphic-ws");
const statusAtom = atom<string[]>({
key: "statusAtom",
default: []
});
function Component() {
const [status, setStatus] = useRecoilState(statusAtom);
const functionCalledAfterButtonPress = () => {
ws.onmessage = function incoming(res: any) {
console.log(res.data); // for debugging
setStatus([...status, res.data]);
};
}
}
请注意,我没有包括其他事件,例如 ws.onopen
和 return 语句或诸如此类的东西,原子声明和组件声明在不同的文件中。
正如 Jayce444 所说,解决这个问题的方法不是使用 setStatus
和已经计算出的值,[...status, res.data]
,我应该传入一个 lambda 语句,当状态为已更新。
而不是:
setStatus([..status, res.data])
使用:setStatus(prevStatus => [...prevStatus, res.data])
我正在构建一个使用 recoiljs 作为我的状态管理器的 React 应用程序,我需要从网络套接字获取数据并相应地更新状态。我不使用常规数组的原因是我需要在我的组件之间共享状态。
详细地说,该组件有一个 WebSocket 连接,并且将有数据流入其中。然后它需要通过推送接收到的数据来更新数组。问题是由于组件生命周期或其他原因,状态写入错误,这就是我认为发生的事情
- 收到响应 1 并调用 setState([...state, data])
- 然后收到响应 2 并调用 setState([...state, data])
- 状态实际上是由Response 1设置的
- 状态由响应 2 设置
问题是当响应 2 进入并调用 setState 时,它有一个旧版本的状态,不包括响应 1。
我似乎不知道如何解决这个问题。这是精简代码。
import {atom} from "recoil"
import {useRecoilState} from "recoil"
const WebSocket = require("isomorphic-ws");
const statusAtom = atom<string[]>({
key: "statusAtom",
default: []
});
function Component() {
const [status, setStatus] = useRecoilState(statusAtom);
const functionCalledAfterButtonPress = () => {
ws.onmessage = function incoming(res: any) {
console.log(res.data); // for debugging
setStatus([...status, res.data]);
};
}
}
请注意,我没有包括其他事件,例如 ws.onopen
和 return 语句或诸如此类的东西,原子声明和组件声明在不同的文件中。
正如 Jayce444 所说,解决这个问题的方法不是使用 setStatus
和已经计算出的值,[...status, res.data]
,我应该传入一个 lambda 语句,当状态为已更新。
而不是:
setStatus([..status, res.data])
使用:setStatus(prevStatus => [...prevStatus, res.data])