reactjs - 基于客户端 Socket.IO 响应的 React/Redux 全局状态管理?
问题描述
我有一个具有多种功能的网络应用程序,例如私人消息传递、购买、优惠等。我想让它实时工作,所以我决定使用 socket.io。我使用 redux 进行全局状态管理,但我不知道如何将它与 socket.IO 结合使用。这是我的想法:
1.使用导出函数创建一个用于套接字处理的文件到 App.js 以创建套接字连接,发送和侦听不同的数据。
2.每当我得到相关的东西,例如通知或购买请求时,我都会更新我的 redux 状态。
3.最后,在我的组件中,我将对那些全局 redux 状态使用 useEffect,如果它发生变化,我将根据我更改的状态重新渲染我的组件。
这是一个好方法吗?如果不是,哪种方法是根据套接字接收到的信息全局管理我的组件的正确方法?
解决方案
一般来说,根据您的需要,我认为这种方法没有任何问题。我将在这里提供一个可操作的示例。我的示例将假设 TypeScript,因为它比其他方式更容易转换为 JavaScript(如果您不使用 TypeScript)。
关于您的第一个问题,我建议建立 Websocket 连接并将其作为上下文传递,因为您在应用程序的任何地方都使用它,并创建自定义挂钩以在任何地方使用该连接:
import React, { createContext, FunctionComponent, ReactNode, useContext, useEffect, useMemo, useState } from 'react';
import io from 'socket.io-client';
export const WebsocketContext = createContext<SocketIOClient.Socket | null>(null);
const WebsocketProvider: FunctionComponent<{ children: ReactNode }> = ({ children }: { children: ReactNode }) => {
const [connection, setConnection] = useState<SocketIOClient.Socket | null>(null);
const options: SocketIOClient.ConnectOpts = useMemo(() => ({}), []);
useEffect(() => {
try {
const socketConnection = io(process.env.BASE_URL || '127.0.0.1', options);
setConnection(socketConnection);
} catch (err) {
console.log(err);
}
}, [options]);
return <WebsocketContext.Provider value={connection}>{children}</WebsocketContext.Provider>;
};
export const useWebsocket = (): SocketIOClient.Socket | null => {
const ctx = useContext(WebsocketContext);
if (ctx === undefined) {
throw new Error('useWebsocket can only be used inside WebsocketContext');
}
return ctx;
};
export default WebsocketProvider;
上面我们创建了具有类型SocketIOClient.Socket
和默认值的上下文null
,因为当连接尚未准备好时,我们必须分配默认值。然后我们创建 Websocket 提供者,FunctionComponent
它接受子节点并通过钩子保持连接状态,useState
最终返回提供者与 Websocket 连接。我还提到SocketIOClient.ConnectOpts
,根据您的需要,您可能希望提供连接选项;使用钩子时静态或动态。此外useEffect
,钩子将尝试建立连接或引发错误。唯一会重新运行此钩子的依赖项是连接选项,以防它们动态更改。
最后,我们有自定义钩子useWebsocket
,我们可以将其导入任何组件并在上下文提供程序中使用。只需使用上下文提供程序包装您的根组件(或任何其他层次结构级别)以提供上下文,如下例所示:
import React, { FunctionComponent } from 'react';
import { BrowserRouter as Router, Switch, Route, Redirect } from 'react-router-dom';
import { v4 as uuid } from 'uuid';
import routes from './App.routes';
import WebsocketProvider from './websocket.context';
const App: FunctionComponent = () => {
return (
<WebsocketProvider>
<Router>
<Switch>
{routes.map((route) => (
<Route key={uuid()} {...route} />
))}
</Switch>
<Redirect to='/' />
</Router>
</WebsocketProvider>
);
};
export default App;
关于您的第二个问题,您可以使用“useEffect”钩子在连接发出时做出反应并更新您的 Redux(或其他全局状态管理)存储。在这里,我还使用 Elvis 运算符来检查连接是否还没有准备好(如果它还没有准备好,因为当它准备好时null
,挂钩将在连接更改时useEffect
重新渲染):socket
import React, { FunctionComponent, useEffect, useState } from 'react';
import { useWebsocket } from './websocket.context';
const Foo: FunctionComponent = () => {
const dispatch = useDispatch();
const socket = useWebsocket();
useEffect(() => {
socket?.on('myEmitEvent', (data: myEmitData) => {
dispatch(myStoreAction(data));
});
return () => {
socket?.off('myEmitEvent');
};
}, [socket, dispatch]);
return ...
};
export default Foo;
关于您提到的第三个问题,您可以使用useEffect
hook 或更简单useSelector
的 hook from react-redux
package 它会自动捕获您的状态更改,从而触发对必要元素的重新渲染。
简而言之,您的想法很成功,我希望通过这个简短的可操作示例,您将能够改进适合您的解决方案。
推荐阅读
- python-3.x - 在我的本地机器上运行时出现 Flask 404 错误
- rest - 通过 REST 将 Azure DevOps 服务器管道的构建状态发送到 Bitbucket
- intellij-idea - java: 你没有使用 lombok 支持的编译器,所以 lombok 将无法工作并且已被禁用
- amazon-web-services - 如何在 AWS 中的安全组内和跨安全组自动使用公共 IP 地址替换分配的入站规则?
- javascript - Bootstrap 选择可编辑组合框黑客
- java - 如何在浏览器中打开pdf文件
- python-3.x - Python等待/暂停直到特定时间......并在计划结束时停止
- python - 如何从函数内的循环中获取向量/数组输出?
- jboss - Wildfly 服务器多个域?
- python - 如何在 tkinter 中删除多边形?