React Router DOM v6路由切换时Wrapper组件无法重新挂载问题
React Router v6中路由切换时Wrapper组件未重新挂载的原因与解决方法
技术栈:react-router-dom v6、React 18.2.0
问题描述
基于以下代码,预期每次路由切换时Wrapper组件都会重新挂载,但实际它始终保持挂载状态,切换路由不会触发新实例的创建,可通过控制台打印的wrapper mounted>>>>日志验证此问题。
import React from "react"; import { BrowserRouter, Routes, Route, Link } from "react-router-dom"; import "./styles.css"; function HomePage() { return <div className="page">🏠 Page</div>; } function Test() { return <div className="page">Test Page</div>; } function ApplePage() { return <div className="page">🍎 Page</div>; } export default function App() { return ( <BrowserRouter> <div> <Link to="/" className="link"> Home </Link> <Link to="/apple" className="link"> Apple </Link> <Link to="/test" className="link"> Test </Link> </div> <Routes> <Route path="/" element={ <Wrapper> <HomePage /> </Wrapper> } /> <Route path="/apple" element={ <Wrapper> <ApplePage /> </Wrapper> } /> <Route path="/test" element={ <Wrapper> <Test /> </Wrapper> } /> </Routes> </BrowserRouter> ); } const Wrapper = ({ children }) => { React.useEffect(() => { console.log("wrapper mounted>>>>"); }, []); return children; };
原因分析
React Router v6在匹配路由时会做组件复用优化:当不同路由的元素属于同一组件类型(这里都是Wrapper),React仅会更新组件的props(比如这里的children),而不会销毁原有组件实例再创建新实例。因此Wrapper的useEffect空依赖回调只会在首次挂载时执行一次,路由切换不会触发重新挂载。
解决方法
要让每个路由对应的Wrapper触发重新挂载,需要让React识别它们为不同的组件实例或类型,以下是两种可行方案:
方案1:为每个Wrapper添加唯一key
React通过key属性区分组件身份,不同的key会触发组件的卸载和重新挂载:
<Routes> <Route path="/" element={ <Wrapper key="home"> <HomePage /> </Wrapper> } /> <Route path="/apple" element={ <Wrapper key="apple"> <ApplePage /> </Wrapper> } /> <Route path="/test" element={ <Wrapper key="test"> <Test /> </Wrapper> } /> </Routes>
方案2:创建独立的路由包装组件
为每个路由单独定义包装组件,让React识别为不同的组件类型,从而触发重新挂载:
// 为每个路由创建专属包装组件 const HomeWrapper = ({ children }) => <Wrapper>{children}</Wrapper>; const AppleWrapper = ({ children }) => <Wrapper>{children}</Wrapper>; const TestWrapper = ({ children }) => <Wrapper>{children}</Wrapper>; // 路由中使用 <Routes> <Route path="/" element={<HomeWrapper><HomePage /></HomeWrapper>} /> <Route path="/apple" element={<AppleWrapper><ApplePage /></AppleWrapper>} /> <Route path="/test" element={<TestWrapper><Test /></TestWrapper>} /> </Routes>
内容的提问来源于stack exchange,提问作者Rohit Raut
相关产品推荐
相关产品推荐

