v6版本升级后路由组件卸载异常排查记录
最近在将项目从React Router v5升级到v6的过程中,遇到了一个棘手的问题:路由组件在切换时出现异常卸载的情况。这个问题在开发环境和生产环境都出现了,严重影响了用户体验。
问题复现步骤
首先,我创建了一个包含多个路由的简单应用:
const App = () => {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/user/:id" element={<UserPage />} />
<Route path="/profile" element={<Profile />} />
</Routes>
</BrowserRouter>
);
};
在UserPage组件中,我使用了useParams hook获取参数:
const UserPage = () => {
const { id } = useParams();
useEffect(() => {
console.log('UserPage mounted', id);
return () => {
console.log('UserPage unmounted');
};
}, [id]);
return <div>User {id}</div>;
};
排查过程
问题出现后,我首先检查了路由配置,发现v6的写法确实与v5不同。但当我切换路由时,控制台会打印出"UserPage unmounted",然后立即又打印"UserPage mounted",这说明组件被异常卸载和重新挂载。
通过调试发现,问题出在嵌套路由的处理上。在v6中,当使用<Outlet />时,如果父路由和子路由同时存在,组件可能会被重复渲染。最终定位到问题是在以下代码中:
<Route path="/user" element={<UserLayout />}>
<Route index element={<UserList />} />
<Route path=":id" element={<UserDetail />} />
</Route>
当从/user/123跳转到/user/456时,由于路由匹配规则的变化,导致了组件的异常卸载。
解决方案
最终通过以下方式解决:
- 使用
useNavigate代替Link进行路由跳转 - 在
<Route>上添加key属性来强制重新渲染 - 重构嵌套路由结构,避免重复匹配
const UserPage = () => {
const navigate = useNavigate();
const { id } = useParams();
useEffect(() => {
console.log('UserPage mounted', id);
return () => {
console.log('UserPage unmounted');
};
}, [id]);
return <div>User {id}</div>;
};
这次升级让我深刻体会到v6的路由机制变化,虽然功能更强大,但需要更仔细地处理路由嵌套和组件生命周期问题。

讨论