3、导航与链接:Link与NavLink组件、activeClassName与activeStyle、编程式导航(useNavigate)
导航,说白了就是让用户在页面之间跳来跳去。React Router 提供了几种方式,我一个个讲给你听。
3.1 Link 组件:最基础的导航
Link 组件是 React Router 里最常用的导航方式。它最终会渲染成一个 <a> 标签,但不会触发页面刷新。
import { Link } from 'react-router-dom';
function Navbar() {
return (
<nav>
<Link to="/">首页</Link>
<Link to="/about">关于我们</Link>
<Link to="/products">产品列表</Link>
</nav>
);
}
to 属性支持字符串和对象两种写法。我个人习惯用字符串,简单直接。但有些场景需要传参数,就得用对象了。
// 字符串写法
<Link to="/users/123">用户详情</Link>
// 对象写法
<Link to={{
pathname: '/users/123',
search: '?tab=profile',
hash: '#bio'
}}>用户详情</Link>
小提示:Link 组件默认会阻止浏览器的默认跳转行为,所以不用担心页面刷新。它内部用的是
history.push 或 history.replace。
3.2 NavLink 组件:带激活状态的导航
NavLink 是 Link 的升级版。它多了一个功能:能自动识别当前路由是否匹配,然后给你加上激活样式。
我在项目中遇到过这样的需求:导航栏里当前选中的菜单要高亮显示。用 NavLink 就特别方便。
import { NavLink } from 'react-router-dom';
function Navbar() {
return (
<nav>
<NavLink to="/" end>首页</NavLink>
<NavLink to="/about">关于我们</NavLink>
<NavLink to="/products">产品列表</NavLink>
</nav>
);
}
注意那个 end 属性。为什么要加它?因为如果不加,当你在 /about 页面时,/ 也会被匹配到。嗯,这里要注意,end 属性表示「精确匹配」,只有路径完全一致时才激活。
activeClassName 和 activeStyle
这两个属性就是用来控制激活样式的。一个是加类名,一个是直接写内联样式。
// 使用 activeClassName
<NavLink
to="/about"
className={({ isActive }) => isActive ? 'active-link' : ''}
>
关于我们
</NavLink>
// 使用 activeStyle(旧版写法,现在推荐用 className 函数)
<NavLink
to="/about"
style={({ isActive }) => ({
color: isActive ? '#ff6b6b' : '#333',
fontWeight: isActive ? 'bold' : 'normal'
})}
>
关于我们
</NavLink>
重要更新:React Router v6 已经废弃了
activeClassName 和 activeStyle 属性。现在推荐用 className 和 style 的回调函数形式。你想想看,这样更灵活,还能根据状态做更多判断。
我曾经在维护一个老项目时,发现代码里还在用 activeClassName,结果升级到 v6 后全报错了。所以建议你直接学新写法。
3.3 编程式导航:useNavigate
有时候你不能用 Link 组件,比如表单提交成功后要跳转,或者倒计时结束后自动跳转。这时候就需要编程式导航。
React Router v6 提供了 useNavigate 这个 Hook,用起来特别顺手。
import { useNavigate } from 'react-router-dom';
function LoginForm() {
const navigate = useNavigate();
const handleSubmit = async (event) => {
event.preventDefault();
// 模拟登录请求
await login();
// 登录成功后跳转到首页
navigate('/');
};
return (
<form onSubmit={handleSubmit}>
<input type="text" placeholder="用户名" />
<input type="password" placeholder="密码" />
<button type="submit">登录</button>
</form>
);
}
navigate 函数支持两个参数:
| 参数 | 类型 | 说明 |
|---|---|---|
| 第一个参数 | string 或 number | 要跳转的路径,或者步数(如 -1 表示后退) |
| 第二个参数 | object(可选) | 配置项,如 replace、state 等 |
// 前进或后退
navigate(-1); // 后退一页
navigate(1); // 前进一页
// 替换当前历史记录
navigate('/dashboard', { replace: true });
// 携带状态数据
navigate('/profile', {
state: { userId: 123, from: 'login' }
});
避坑指南:我曾经在 useEffect 里直接调用 navigate,结果控制台报了一堆警告。为什么?因为 navigate 会触发组件重新渲染,容易造成死循环。正确的做法是:在事件处理函数或回调里调用,或者用 useEffect 的依赖数组控制好时机。
3.4 三种导航方式的对比
| 方式 | 适用场景 | 特点 |
|---|---|---|
| Link | 静态导航链接 | 简单、声明式、无激活状态 |
| NavLink | 需要高亮当前菜单 | 自动匹配路由、支持激活样式 |
| useNavigate | 表单提交、定时跳转、条件跳转 | 灵活、可在任意函数中调用 |
说白了,能用 Link 和 NavLink 的地方,尽量别用编程式导航。声明式写法更清晰,也更容易维护。但遇到需要「在代码里决定跳不跳」的场景,useNavigate 就是你的好帮手。
我的习惯:导航栏用 NavLink,普通链接用 Link,业务逻辑里的跳转用 useNavigate。这样分工明确,代码也容易读。
嗯,导航这块内容就这些。你想想看,其实核心就三个点:Link 做基础导航,NavLink 做高亮导航,useNavigate 做灵活跳转。掌握了这些,大部分导航需求都能搞定。