本文最后更新于: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