「这是我参与2022首次更文挑战的第1天,活动详情查看:2022首次更文挑战」
React Router应该是React生态系统中最受欢迎的库了,npm周下载量达600w+,github也有45.2k的加星,足以说明它是一款非常优秀的库,作为React社区重要的库,它经历了多次迭代和重大更改,就在上个月,更是迎来了一个大的正式版更新6.x,当前最新为6.0.2,相对比于之前的5.x版本做出了较大改变,不管从用法还是从性能上都有了明显的提升,本文也将用新老版本对比的方式让你能以最快的速度上手新用法
本文将围绕以下6点来学习react-router@6:
<Route/>用法变化<Switch/>替换为<Routes/>- 嵌套路由新写法
- 如何实现路由重定向
- 如何实现路由跳转
- 全新Hook的使用
<Route/>用法变化
<Route/>组件变化较大,移除了component与render属性,使用element属性替代,因此与之前的版本代码写法不兼容
// 5.x用法
<Route path="/home" component={Home} />
<Route path="/login" render={()=><Login/>}/>
// 6.x用法
<Route path="/home" element={<Home/>} />
<Route path="/login" element={<Login/>} />
<Switch/>替换为<Routes/>
v6版本移除了<Switch/>组件,并使用<Routes/>替换,除了能替代<Switch/>组件的功能外,也做了一些改变,比如所有的<Route>都必须包裹在<Routes/>中,否则抛出错误
// 5.x用法
<Switch>
<Route path="/home" component={Home} />
<Route path="/login" component={Login} />
</Switch>
// 6.x用法
<Routes>
<Route path="/home" element={<Home/>} />
<Route path="/login" element={<Login/>} />
</Routes>
嵌套路由
v6版本的react-router支持多种嵌套路由写法,写法分别如下:
-
第一种写法:延续v5版本写法,保持原有组件结构
这种写法比较适合重构的项目,不需要改变太多的代码便能过渡到v6版本
// App.jsx <Routes> <Route path="/home" element={<Home/>} /> <Route path="/user/*" element={<User/>} /> </Routes> // User.jsx <Routes> <Route path="profile" element={<UserProfile/>} /> <Route path=":/id" element={<UserDetail/>} /> </Routes>虽然组件结构与v5版本一至,但写法上有一定的差异,父组件
App.jsx中<Route>的path属性最后必须使用星号(path="/user/*"),且子组件User.jsx中的路径不需要以/开头如果嵌套的
<Route/>的path属性不以/开头,则是相对于其父级路径,这样的好处是使嵌套路由实现变得更加简单,并易于组合复杂的路由和布局,所以不需要像v5版本那样写全整个路径,妈妈再也不用担心我会写错地址了
-
第二种写法:把所有的
<Route/>写在一起,配合<Outlet/>实现路由组件的显示// App.jsx <Routes> <Route path="/home" element={<Home/>} /> <Route path="/user" element={<User/>}> <Route path="profile" element={<UserProfile/>} /> <Route path=":/id" element={<UserDetail/>} /> </Route> </Routes> // User.jsx <Outlet/>这样写法让我们能更清晰地去了解路由结构,能更好地管理我们的路由,而
<Outlet/>能让我们能更精确地把嵌套的路由组件布局到需要显示的位置(如上代码:<UserProfile/>和<UserDetail/>在路由匹配时就会显渲染到User.jsx文件中<Outlet/>所在的位置)如果想让用户访问
/user时默认渲染某个路由,则可以在<Route/>组件中添加index属性设置成默认路由,如下:当用户访问/user时,渲染<UserProfile/>组件内容// App.jsx <Routes> <Route path="/home" element={<Home/>} /> <Route path="/user" element={<User/>}> <Route path="profile" element={<UserProfile/>} index /> <Route path=":/id" element={<UserDetail/>} /> </Route> </Routes> -
第三种写法:使用
useRoutes()实现路由配置使用
useRoutes配置路由与<Routes/>配置路由效果一致,只是这种写法使用javascript生成路由,不依赖JSX,返回相应结构的路由组件树,有木有感觉回到了VueRouter?有木有?function App(){ // 以下写法与第二种写法效果一至 const element = useRoutes([ {path:'/home',element:<Home/>}, { path:'/user', element:<User/>, children:[ {path:'profile',element:<UserProfile/>}, {path:':/id',element:<UserDetail/>}, ] } ]) return element }
以上三种写法各有各的优点,开发者可以根据自身的需求选择一种来实现你的嵌套路由
重定向
新版本的react-router移除了<Redirect/>组件,但可以使用新增的<Navigate/>组件配合<Route/>组件实现重定向效果
<Routes>
<Route path="/home" element={<Home/>} />
<Route path="/" element={<Navigate to="/home"/>}>
</Routes>
路由跳转
路由配置好后免不了要进行页面跳转,但新版的react-router移除了history对象,故不能使用v5版本的history(包括useHistory hook)已不能使用,我们可以使用以下两中方式进行跳转
-
使用
<Link>或<NavLink>进行跳转 这种方式与上一个版本几乎没有太大的区别,唯一的区别是<NavLink>组件的高亮写法发生了变化(使用style或className回调函数的方式实现高亮,用法如下)// v5版本 <NavLink to="/home" activeStyle={{color:'#f00'}}>首页</NavLink> <NavLink to="/home" activeClassName="active">首页</NavLink> // v6版本 <NavLink to="/home" style={({isActive})=>(isActive?{color:'#f00'}:{})}>首页</NavLink> <NavLink to="/home" className={({isActive})=>isActive?'current':''}>首页</NavLink>PS:
<NavLink/>默认已经有一个用于高亮的active类,可以直接使用,不需要额外设置 -
使用
useNavigate()进行跳转 有时候我们并不能使用以上两个组件进行跳转,如根据ajax请求返回值跳转不同的页面,这时我们就得使用js的方式时行跳转了,虽然新版的react-router已经移除掉history对象,但给我们提供了useNavigate()hook实现路由跳转,使用方法如下import { useNavigate } from "react-router-dom"; let navigate = useNavigate(); navigate(`/home`); // 跳转且不保留浏览记录 navigate(`/home`,{replace:true}); // 返回上一页 navigate(-1) // 对象方式跳转 navigate({ pathname:'/home' })需要注意一点就是,在v6版本的react-router中,如果跳转的路径如果不是以
/开头,则为相对路径,相对于其父级路由路径,这样的设置能让我们更好的控制跳转
路由传参
我们都知道,在进行路由跳转时,可以通过附带一些参数一起传递到目标页面来实现某些特殊功能,但新版的react-router已经从props中移除了history、location、match,也移除掉了withRouter高阶组件,所以无法使用老版本的方式传参与接收,新版用法如下
-
search传参
let navigate = useNavigate(); navigate(`/home?page=1&size=10`); navigate({ pathname:'/home', search:'page=1&size=10' });在对应组件接收参数也很简单,使用
useSearchParamshook进行接收,得到URLSearchParams对象以及设置search参数函数组成的数据function Home(){ const [searchParams,setSearchParams] = useSearchParams() searchParams.get('page');//1 searchParams.get('size');//10 return ( <div>首页</div> ) } -
动态路由传参
<Route path="/user" element={<User/>}> <Route path=":/id" element={<UserDetail/>} /> </Route>配置完以上路由后,当页面跳转到
/user/123这个路径时,可以在<UserDetail/>组件中使用useParamshook获取123这个idfunction UserDetail(){ const {id} = useParams() return ( <div>id:{id}</div> ) } -
state传参 通过
<Link/>、<NavLink/>或useNavigate进行跳转时,都可以传递state参数,用法如下:<Link to="/home" state={{idx:1,key:'qf'}}>首页</Link> navigate('/home',{state:{idx:1,key:'qf'}})在首页组件中通过
useLocationhook获取state值function Home(){ const {state} = useLocation(); state.idx; // 1 state.key; // qf return ( <div>首页</div> ) }
其他
另外,React路由同样支持SSR服务端渲染等其它功能,由于篇幅在限,在此不做过多说明,感兴趣的小伙伴请继续关注我,后续的写文章专门介绍react-router在在服务端的用法。
总结
以上就是本文的所有内容,希望通过该文章能让大家对新版本react-router6有个全面的认识,以便在项目中应用新版路由。
详情请看react-router官网文档:reactrouter.com/docs/en/v6