React 中的导航:不仅仅是点击链接
您是否曾想过,如何让 React Router 不是通过用户点击,而是通过代码指令跳转到另一个页面?例如,在成功提交表单、用户认证后,或者仅仅是在 5 秒后?如果是这样,那么您来对地方了。“如何使用 React Router 进行程序化导航?”这个问题是 Stack Overflow 上最热门的问题之一,这并非偶然。看起来很简单,但实际上隐藏着许多陷阱,尤其是在涉及性能时。
在本文中,我们不仅会展示如何使用 useNavigate。我们还将分析如何 正确、快速且无延迟地做到这一点。您将了解哪些模式会导致内存泄漏,哪些模式能实现闪电般的导航。我们开始吧!
经典方法:useNavigate — 您的主要工具
从 React Router v6 开始,useNavigate 取代了旧的 useHistory。这是一个返回 navigate 函数的 Hook。看起来像这样:
import { useNavigate } from 'react-router-dom';
function LoginButton() { const navigate = useNavigate();
const handleLogin = () => { // 这里是认证逻辑 const user = { name: 'Ivan' }; // 成功后重定向 navigate('/dashboard', { replace: true }); };
return <button onClick={handleLogin}>登录</button>;}请注意参数 { replace: true }。它会替换历史记录中的当前条目,而不是添加新条目。这对于登录至关重要,可以防止用户后退到登录页面。
可以导航到哪里?
- 绝对路径:
navigate('/about') - 相对路径:
navigate('../settings') - 历史记录中的前进/后退:
navigate(-1)或navigate(2)
进阶:在组件外部进行导航
如果您需要从普通函数(而不是 React 组件内部)进行重定向,该怎么办?例如,从 Redux 的 action creator 或 axios 拦截器中?useNavigate Hook 在这里不起作用——Hook 只能在函数式组件内部调用。
解决方案:创建一个自定义包装组件,或者使用 全局路由器对象。在 React Router v6 中,有专门的 RouterProvider 组件和 createBrowserRouter,但还有一种更简单的方法——将 navigate 的引用保存在一个变量中。
// router.jsimport { createBrowserRouter, RouterProvider } from 'react-router-dom';
export const router = createBrowserRouter([...]);
// navigation.js — 用于导航的独立模块let navigateFunction = null;
export const setNavigate = (navigate) => { navigateFunction = navigate;};
export const navigateTo = (path) => { if (navigateFunction) { navigateFunction(path); } else { console.warn('导航尚未就绪'); }};
// App.jsimport { useNavigate } from 'react-router-dom';import { setNavigate } from './navigation';import { useEffect } from 'react';
function App() { const navigate = useNavigate();
useEffect(() => { setNavigate(navigate); }, [navigate]);
return /* 您的代码 */;}现在,您可以从任何函数(无论是 setTimeout 还是 fetch)中调用 navigateTo('/home')。方便吗?是的。安全吗?只有当您记得在组件卸载时清除引用时才安全。
性能优化:为什么您的应用程序会卡顿?
程序化导航不仅仅是调用一个函数。它会触发页面的完全重新渲染。如果您这样做