每当有新状态时,我都想在以前的状态上应用功能。 用户案例:用户与服务器建立连接。我创建一个WebSocket对象,并将其放入webSocketInstance中。当用户输入用户名时,我将该名称添加到Redux中,这将导致重新呈现组件,这是可以的。现在,由于他具有用户名,因此我希望他使用新的URL重新连接(也是重新连接逻辑的这一部分)。所以我要他关闭以前的连接并打开一个新的连接。
export default function GameKeeper() {
// Redux states here
const { adminWsUrl, clientWsUrl, clientCode, playerName } = useSelector(
(state: RootState) => state.hosting
);
const [webSocketInstance, setWebSocketInstance] = useState<WebSocket>();
useEffect(() => {
if (webSocketInstance) {
webSocketInstance.close();
}
if (adminWsUrl) {
setWebSocketInstance(new WebSocket(adminWsUrl));
} else if (clientWsUrl && playerName) {
setWebSocketInstance(new WebSocket(`${clientWsUrl}${playerName}/`));
} else if (clientWsUrl && !playerName) {
setWebSocketInstance(new WebSocket(clientWsUrl));
}
}, [adminWsUrl, clientWsUrl, playerName]);
return (
...
);
}
当前代码警告我webSocketInstance不在useEffect依赖项中。如果添加它,则会出现无限循环。
答案 0 :(得分:1)
这是我如何设置useReducer
来处理此问题的基本模板。我真的想不出一种仅通过useState
来完成此操作的好方法,而又没有利用某些可变状态(即useRef
)来保存Web套接字。当然,这样做的缺点是您已经完全摆脱了React的状态系统,无法再监视套接字进行更新了。
function wsReducer(wsInstance, action) {
if (action.type === "reset") {
wsInstance && wsInstance.close();
return new WebSocket(action.payload);
}
}
export default function App() {
const { adminWsUrl, clientWsUrl, clientCode, playerName } = useSelector(
(state: RootState) => state.hosting
);
const [wsInstance, dispatch] = useReducer(wsReducer, null);
useEffect(() => {
const url = (() => {
if (adminWsUrl) return adminWsUrl;
if (clientWsUrl && playerName) return `${clientWsUrl}${playerName}/`;
if (clientWsUrl && !playerName) return clientWsUrl;
return false;
})();
if (url) {
dispatch({ type: "reset", payload: url });
}
}, [adminWsUrl, clientWsUrl, playerName]);
return (
...
);
}
此外,还有一些recommended reading-尤其是有关在这种情况下解耦更新/操作并使用useReducer
的内容。我建议尝试通读一下整个内容,当我开始进行功能性React时,这对我来说真的很有用。