MrN*_*ody 1 socket.io reactjs redux
我有一个具有多种功能的网络应用程序,例如私人消息、购买、优惠等。我想让它实时工作,所以我决定使用 socket.io。我使用 redux 进行全局状态管理,但我不知道如何将其与 socket.IO 结合起来。这是我的想法:
1.创建一个用于套接字处理的文件,并使用导出到 App.js 的函数来创建套接字连接,发送和侦听不同的数据。
2.每当我收到相关信息(例如通知或购买请求)时,我都会更新我的 redux 状态。
3.最后,在我的组件中,我将使用 useEffect 来处理这些全局 redux 状态,如果它发生变化,我将根据更改后的状态重新渲染我的组件。
这是一个好方法吗?如果不是,哪种是根据套接字收到的信息全局管理我的组件的正确方法?
一般来说,根据您的需求,我认为这种方法没有任何问题。我将在这里提供一个可操作的示例。我的示例将假设使用 TypeScript,因为它比其他方式更容易转换为 JavaScript(如果您不使用 TypeScript)。
\n关于您的第一个问题,我建议建立并传递 Websocket 连接作为上下文,因为您在应用程序中的任何地方都使用它,并创建自定义挂钩以在任何地方使用连接:
\nimport React, { createContext, FunctionComponent, ReactNode, useContext, useEffect, useMemo, useState } from 'react';\nimport io from 'socket.io-client';\n\nexport const WebsocketContext = createContext<SocketIOClient.Socket | null>(null);\n\nconst WebsocketProvider: FunctionComponent<{ children: ReactNode }> = ({ children }: { children: ReactNode }) => {\n const [connection, setConnection] = useState<SocketIOClient.Socket | null>(null);\n\n const options: SocketIOClient.ConnectOpts = useMemo(() => ({}), []);\n\n useEffect(() => {\n try {\n const socketConnection = io(process.env.BASE_URL || '127.0.0.1', options);\n setConnection(socketConnection);\n } catch (err) {\n console.log(err);\n }\n }, [options]);\n\n return <WebsocketContext.Provider value={connection}>{children}</WebsocketContext.Provider>;\n};\n\nexport const useWebsocket = (): SocketIOClient.Socket | null => {\n const ctx = useContext(WebsocketContext);\n if (ctx === undefined) {\n throw new Error('useWebsocket can only be used inside WebsocketContext');\n }\n return ctx;\n};\n\nexport default WebsocketProvider;\nRun Code Online (Sandbox Code Playgroud)\n上面我们创建了具有类型SocketIOClient.Socket且默认为 的上下文null,因为当连接尚未准备好时,我们必须分配默认值。然后我们创建 Websocket 提供程序,FunctionComponent它接受子级并通过useState钩子保持连接状态,最终返回具有 Websocket 连接的提供程序。我还提到SocketIOClient.ConnectOpts,根据您的需求,您可能需要提供连接选项;使用钩子时静态或动态。此外useEffect钩子将尝试建立连接或抛出错误。将重新运行此挂钩的唯一依赖项是连接选项,以防它们动态更改。
最后,我们有自定义钩子useWebsocket,我们可以将其导入到任何组件中并在上下文提供程序中使用。只需使用上下文提供程序包装根组件(或任何其他层次结构级别)即可提供上下文,如下例所示:
import React, { FunctionComponent } from 'react';\nimport { BrowserRouter as Router, Switch, Route, Redirect } from 'react-router-dom';\nimport { v4 as uuid } from 'uuid';\nimport routes from './App.routes';\nimport WebsocketProvider from './websocket.context';\n\nconst App: FunctionComponent = () => {\n return (\n <WebsocketProvider>\n <Router>\n <Switch>\n {routes.map((route) => (\n <Route key={uuid()} {...route} />\n ))}\n </Switch>\n <Redirect to='/' />\n </Router>\n </WebsocketProvider>\n );\n};\n\nexport default App;\nRun Code Online (Sandbox Code Playgroud)\n关于你的第二个问题,你可以使用 \xc2\xb4useEffect\xc2\xb4 钩子在连接发出时做出反应并更新你的 Redux (或其他全局状态管理)存储。在这里,我还使用 Elvis 运算符来检查连接是否尚未准备好(如果尚未准备好,因为准备好后挂钩将在连接更改时null重新useEffect渲染):socket
import React, { FunctionComponent, useEffect, useState } from 'react';\nimport { useWebsocket } from './websocket.context';\nconst Foo: FunctionComponent = () => {\n const dispatch = useDispatch();\n const socket = useWebsocket();\n\n useEffect(() => {\n socket?.on('myEmitEvent', (data: myEmitData) => {\n dispatch(myStoreAction(data));\n });\n return () => {\n socket?.off('myEmitEvent');\n };\n }, [socket, dispatch]);\n\n return ...\n};\n\nexport default Foo;\nRun Code Online (Sandbox Code Playgroud)\n关于您提到的第三个问题,您可以使用useEffect钩子或更简单地useSelector使用包中的钩子react-redux,它会自动捕获您的状态更改,从而触发必要元素的重新渲染。
简而言之,您的想法很准确,我希望通过这个简短的可操作示例,您将能够完善适合您的解决方案。
\n| 归档时间: |
|
| 查看次数: |
2225 次 |
| 最近记录: |