路由切换时WebSocket高层组件反复卸载问题求助
解决WebSocket连接反复重建/卸载的问题
核心问题原因
你目前使用location.href进行路由跳转,这会触发整个页面刷新——React应用会被完全销毁后重新初始化,所以WebSocketProvider里的useEffect每次都会重新执行,导致socket连接反复创建。
另外之前Navbar随路由切换挂载卸载的问题,确实是因为未使用嵌套路由,但现在的主要矛盾是页面刷新导致的WebSocket连接重置。
解决方案
1. 改用SPA内路由跳转,避免页面刷新
替换location.href为react-router-dom提供的useNavigate钩子,这样跳转不会刷新整个页面:
// 在需要跳转的组件中导入useNavigate import { useNavigate } from 'react-router-dom'; function YourComponent() { const navigate = useNavigate(); // 触发跳转的函数示例 const goToProfile = () => { navigate('/profile'); // 替换为你的目标路由路径 }; }
2. 给WebSocket添加卸载清理逻辑
在WebSocketContext的useEffect中加入清理函数,确保组件卸载时关闭socket连接,避免内存泄漏:
修改WebSocketContext.jsx:
import React, { createContext, useContext, useRef, useEffect } from 'react'; import { io } from 'socket.io-client'; const WebSocketContext = createContext(); export const WebSocketProvider = ({ children }) => { const socketRef = useRef(null); const websocketServer = import.meta.env.VITE_API_WSS_URL + '/notifications' useEffect(() => { if (!socketRef.current) { socketRef.current = io(websocketServer, { transports : ['websocket'] }); console.log('WebSocket connected'); } // 组件卸载时关闭连接 return () => { if (socketRef.current) { socketRef.current.disconnect(); socketRef.current = null; console.log('WebSocket disconnected'); } }; }, []); return ( <WebSocketContext.Provider value={socketRef.current}> {children} </WebSocketContext.Provider> ); }; export const useWebSocket = () => useContext(WebSocketContext);
3. 用嵌套路由修复Navbar反复挂载卸载问题
将Navbar放在布局组件中,通过嵌套路由让它始终处于挂载状态:
修改Main.jsx中的router配置:
// 先导入布局组件和页面组件 import NavbarLayout from './components/NavbarLayout'; import Home from './components/Home'; import Profile from './components/Profile'; const router = createBrowserRouter([ { path: '/', element: <NavbarLayout />, // 包含Navbar的根布局 children: [ // 所有页面路由作为子路由 { path: '', element: <Home /> }, { path: 'profile', element: <Profile /> }, // 其他路由... ] } ]);
创建NavbarLayout.jsx:
import { Outlet } from 'react-router-dom'; import Navbar from './Navbar'; export default function NavbarLayout() { return ( <div> <Navbar /> {/* Navbar会始终挂载,不会随子路由切换卸载 */} <Outlet /> {/* 渲染当前子路由对应的页面组件 */} </div> ); }
内容的提问来源于stack exchange,提问作者Andrew Marabante
相关产品推荐
相关产品推荐

