本文最后更新于:2023年1月12日 下午
概述
react router目前已经更新到v6版本,该版本不仅使用TypeScript
进行了重构,而且还新增了很多的功能,其与v5版本可以说已完全没有关联。
现在v6已成为默认安装版本。
react router v6分为3个包:
- react-router: 包含核心功能
- react-router-dom: web端使用的包
- react-router-native: rn端使用的包
react-router-dom和react-router-native已经自动引入了react-router,所以我们在开发时,只需要安装对应开发环境的包即可
引用路由组件
对于web端,支持两种形式的路由:
<HashRouter />
: hash路由,当路由发生改变不会重新向服务端发起请求
<BrowserRouter />
: 使用浏览器内置历史堆栈进行导航
新的组件已不再需要显示添加history,其已经在组件内部实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| import {HashRouter, Routes, Route} from 'react-router-dom'
function App() { return( <HashRouter> <Routes> <Route path='/' element={<Home />}> <Route path='/about' element={<About />}> </Routes> </HashRouter> ) }
// 不使用hash import {BrowserRouter, Routes} from 'react-router-dom'
function App() { return( <BrowserRouter> <Routes> <Route path='/' element={<Home />}> <Route path='/about' element={<About />}> </Routes> </BrowserRouter> ) }
|
注意,如果不使用hash,则每个路由必须要有一个与之对应的服务端路由,否则会出现404
<NativeRouter />
: React Native端使用的路由
<MemoryRouter />
: 其将路由存储在一个数组中,不依赖外部源,可以适合各种场景,例如测试环境下
<Routes />
检查与之匹配的path,并渲染对应的<Route />
<Route />
渲染匹配path的React Element
路由跳转
<Link />
其内部会渲染一个a标签,点击会跳转到对应的路由
1
| <Link to='/home'>跳转到home路径</Link>
|
<NavLink />
是一个特殊的<Link />
组件,常用于渲染导航栏选中时的高亮
1 2 3
| <NavLink style={({isActive: boolean}) => isActive ? 'blue' : 'white'}> Home </NavLink>
|
<Navigate />
对useNavigate()
的封装
这个组件只是为了在Class组件写法中使用,如果是使用Function组件,建议使用hooks写法
useNavigate()
:
改变路由:
1 2 3 4 5 6 7 8 9 10
| const navigate = useNavigate();
navigate('/login');
navigate('/login', {replace: true});
navigate(-1);
|
使用嵌套路由
<Outlet />
实现嵌套路由的渲染
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| ReactDom.render( <Routes> <Route path='/' element={<App />}> <Route path='/home' element={<Home />} /> </Route> </Routes>, document.getElementById('root'); );
function App() { return( <div> <p>渲染App组件<p> {/**如果不添加这个,当path匹配/home时,页面将不会渲染Home组件**/} <Outlet /> </div> ); }
|
useOutlet()
返回路由层次结构中此级别的子路由的元素, <Outlet />
的hooks版
1 2 3 4 5 6 7 8 9 10 11
| function App() { const outlet = useOutlet(); return( <div> <p>渲染App组件<p> {/**如果不添加这个,当path匹配/home时,页面将不会渲染Home组件**/} {outlet} </div> ); }
|
useOutLetContext()
用来向子组件传递属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| function App() { const [message, setMessage] = useState(""); return ( <div> <p>渲染App组件<p> {/**通过context向子组件广播属性**/} <Outlet context={[message, setMessage]} /> </div> ); }
// Home.js function Home() { // 子组件通过useOutletContext() 拿到父组件传递的属性 const [message, setMessage] = useOutletContext(); return ( <div> home <p>{message}</p> <input onChange={(e) => setMessage(e.target.value)} /> </div> ); }
|
Index Routes 概念
什么叫”index route”?
- index route 渲染在父路由的outlet
- 当一个父路由被匹配时,其他子路由都未被匹配,将会匹配index route,
- index route 是父路由的默认子路由
- 如果用户尚未点击导航的任何一个路由时,index route将会被渲染
可能我理解的不是很准确,可以查看官方的解释
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| ReactDom.render( <Routes> <Route path='/' element={<App />}> <Route path='/home' element={<Home />} /> <Route path='/about' element={<About />}> </Route> </Routes>, document.getElementById('root'); ); // App.js function App() { return( <div> <p>渲染App组件<p> {/**如果不添加这个,当path匹配/home时,页面将不会渲染Home组件**/} <Outlet /> </div> ); }
|
对于上面的例子,当path为’/‘时,此时的渲染组件为:
如果添加一个Index Route路由:
1 2 3 4 5 6 7 8 9 10
| ReactDom.render( <Routes> <Route path='/' element={<App />}> {/** Index Route **/} <Route index element={<Home />} /> <Route path='/about' element={<About />}> </Route> </Routes>, document.getElementById('root'); );
|
当path=’/‘时,此时渲染的组件为:
Not Found Routes 概念
当没有路由能够匹配,我们常常会添加一个NotFound页面:
1 2 3 4
| <Routes> <Route path='/' element={<Home />}> <Route path='*' element={<NotFound />}> </Routes>
|
path='*'
将匹配所有的URL,但优先级最低,只有不存在匹配的路由时才会匹配它(尝试了下,这个匹配完全不依赖放置的顺序,即你可以任意放置path='*'
路由的位置🤔感觉比以前好用了,心智模式至少得到了降低)
hooks
这里介绍前面没有介绍的hook
useHref()
传入一个To
类型的数据,返回一个拼好的URL, 可以用来放在属性to
的位置
1 2 3 4 5 6 7 8 9 10 11
|
const to: To = { pathname: "/123456", search: "a=b&c=d", hash: "home" };
const href = useHref(to);
<Link to={href} />
|
useLinkClickHandler()
返回一个点击事件回调,通常用于自定义<Link />
组件
1 2 3
| const handleClick = useLinkClickHandler(to);
<div onClick={handleClick}>点我跳转</div>
|
useLinkPressHandler()
同useLinkClickHandler(), 这是用于rn端的
useInRouterContext()
用于判断组件是否在<Router />
中渲染, true为是,false为否
1 2 3 4 5
| const isInRouterRender = useInRouterContext();
<div> {isInRouterRender ? '组件渲染在<Router />中' : '组件可能飞了'} </div>
|
useNavigationType()
返回进入当前页面的类型或当前导航类型
1
| type NavigationType = "POP" | "PUSH" | "REPLACE";
|
页面初次加载是NavigationType为’POP’类型, 后面如果不设置,默认是’PUSH’类型
useMatch()
返回给定路径上相对于当前位置的路由的匹配数据。
1 2 3 4 5 6 7 8 9 10 11 12 13
| interface PathMatch<ParamKey extends string = string> { params: Params<ParamKey>; pathname: string; pattern: PathPattern; }
interface PathPattern { path: string; caseSensitive?: boolean; end?: boolean; }
const match: PathMatch<ParamKey> | null = useMatch('/home');
|
useParams()
返回当前URL中的params,并组成一个键/值对对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| import * as React from 'react'; import { Routes, Route, useParams } from 'react-router-dom';
function ProfilePage() { let { userId } = useParams(); }
function App() { return ( <Routes> <Route path="users"> <Route path=":userId" element={<ProfilePage />} /> <Route path="me" element={...} /> </Route> </Routes> ); }
|
useResolvedPath()
返回一个解析后的Path对象
1 2 3 4 5 6 7
| declare function useResolvedPath(to: To): Path;
interface Path { pathname: string; search: string; hash: string; }
|
useRoutes()
等同于<Routes />
,接收一个和<Route />
一样参数的对象组成的数组,还是看例子吧:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| function Root() { const element = useRoutes([ { path: '/', element: <App />, children: [ { path: '/home', element: <Home /> }, { path: '/about', element: <About /> } ] }, { path: "team", element: <AboutPage /> } ]);
return element; }
ReactDOM.render(<Root />, document.getElementById('root'));
|
useSearchParams()
用来操作URL的search参数,从此我们不在需要自己去写一个解析search的工具函数了。使用方式与React.useState一样:
1 2 3 4 5 6 7 8 9 10 11
| const [searchParams, setSearchParams] = useSearchParams();
searchParams.get('id');
searchParams.getAll('id');
setSearchParams({id: 2});
|
searchParams是一个URLSearchParams类型实例, setSearchParams其效果与navigate(useNavigate()的返回值)类似,只是前者只改变url的search段
关于URLSearchParams类型实例,详情查看 https://developer.mozilla.org/zh-CN/docs/Web/API/URLSearchParams
注意URLSearchParams的兼容性
useLocation()
返回当前所在页面的location对象(和window.location还是有区别的)。可以用来处理一些当前页面的location发生改变时的副作用
有些api并没有在这里提及
参考
[1] react router官网 https://reactrouter.com/docs/en/v6/api