一文学会react-router-6-看不懂给我一拳

593 阅读6分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第14天,点击查看活动详情

1.react-router-6安装与配置

react-router-6的推出让react伙伴们是爱恨交加啊,大家不禁沉思他娘又出一个版本,刚学会一个版本就推出下一个版本,不过大家不必有淡淡的忧伤,这次更新是对react-router的瘦身,去除了许多react-router5臃肿和复杂的路由机制。因此它实际让我们学习更快,上手更容易,并且了解vue的伙伴们会发现react-router6已经和vue的路由基本趋于一致了。是不是很意外,废话不多说上车。

安装

npm install react-router-dom@6

简单配置

index.js

import React from 'react';
import App from './App';
//1.选择路由模式
import { BrowserRouter,HashRouter } from "react-router-dom";
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  //2.组件包裹
  <BrowserRouter>
    <App />
  </BrowserRouter> 
);

App.js

import { Routes,Route } from "react-router-dom";
import Home from "./views/Home"
import Header from "./views/Header"
import Main from "./views/Main"
import Footer from "./views/Footer"
function App() {
  return (
    <Routes>
      <Route path="/" element={<Home></Home>}></Route>
      <Route path="/header" element={<Header></Header>}></Route>
      <Route path="/main" element={<Main></Main>}></Route>
      <Route path="/footer" element={<Footer></Footer>}></Route>
    </Routes>
  );
}

export default App;

效果展示

1.gif

2. 路由跳转方式

1. Link组件

使用方式: to表示传递的路由地址

<Link to='/index'></Link>

示例

Home.js

import { NavLink,Link } from "react-router-dom"
export default function Home() {
  return <div>
    <div><Link to='/header'>header</NavLink></div>
    <div><Link to='/main'>main</Link></div>
    <div><Link to='/footer'>footer</Link></div>
  </div>
}

Header.js

import { Link } from "react-router-dom"
export default function Header() {
  return <div>
    header
    <Link to='/'>返回首页</Link>
  </div>
}

效果展示

2.gif

2. NavLink组件

NavLink组件和Link组件都是用于路由跳转的。可能有人疑惑为什么功能一样还要出个NavLink? 其实NavLink还有一个逆天属性,我个人感觉十分好用。它可以携带激活属性,它可以判断是否当前路由和自己需要跳转的路由一致性,据此我们可以设置激活后的路由样式。

使用

style属性传递是一个回调函数,回调函数的参数记录了当前页面路由和NavLink指向的路由是否是一个,如果是一个则e.isActive返回true。

<NavLink to='/' style={(e)=>{console.log(e.isActive)}}>

需求

注意看下面图片的tarbar。我们需要根据选择的tarbar跳转对应的路由,然后激活路由选中的样式。 如果用NavLink是十分十分十分简单的。

1.jpg.png

设计思路

将tarbar抽离成一个组件,使用NavLink自带样式激活特性完成。需要显示tabar的页面直接导入tarbar组件就可以。

App.js:全局路由定义

import { Routes,Route } from "react-router-dom";
import Home from "./views/Home"
import Header from "./views/Header"
import Footer from "./views/Footer"
function App() {
  return (
    <Routes>
      <Route path="/" element={<Home></Home>}></Route>
      <Route path="/header" element={<Header></Header>}></Route>
      <Route path="/footer" element={<Footer></Footer>}></Route>
    </Routes>
  );
}

export default App;

Nav.js: 负责tarbar组件切换

import { NavLink } from "react-router-dom";
import "./style.css"
export default function Nav() {
  return (
    <div className="nav">
      <NavLink to='/' style={({ isActive }) => { return isActive ? { color: "red" } : null }}>首页</NavLink>

      <NavLink to='/header' style={({ isActive }) => { return isActive ? { color: "red" } : null }}>头部</NavLink>

      <NavLink to='/footer' style={({isActive})=>{return isActive?{color:"red"}:null}}>尾部</NavLink>
    </div>
  )
}

Home.js:home页面

import Nav from "./Nav" 
export default function Home() {
  return <div>
    home
    <Nav/>
  </div>
}

Header.js:header页面

import Nav from "./Nav" 
export default function Header() {
  return <div>
    header
    <Nav/>
  </div>
}

Footer.js:footer页面

import Nav from "./Nav" 
export default function Footer() {
  return <div>
    footer
    <Nav/>
  </div>
}

效果展示

3.gif

是不是十分十分十分的简单和方便,我们无需使用js和css去判断是否路由显示,而且当页面手动触发到某个路由时,tarbar也会自己处理激活。

3.useNavigate方法

上面两个是通过组件完成的路由切换和跳转,下面介绍的useNavigate是通过js完成路由跳转

使用

import { useNavigate } from "react-router-dom"
const nav = useNavigate()
nav("index")//跳转到index路由
nav(1)//前进
nav(-1)//后退

Home.js

import { useNavigate } from "react-router-dom"
export default function Home() {
  const nav = useNavigate()
  
  //跳转到header页面
  const goHeader = () => {
    nav("header")
  }

  return <div>
    home
    <div onClick={goHeader}>跳转到header</div>
  </div>
}

Header.js

import { useNavigate } from "react-router-dom"
export default function Header() {
  const nav = useNavigate()
  
  //返回上一层
  const goBack = () => {
    nav(-1)
  }
  return <div>
    header
    <div onClick={goBack}>返回上一页</div>
  </div>
}

页面展示

4.gif

3.路由参数

路由中我们可以传递动态参数,通常路由的动态参数主要有两类

//第一类
localhost:3000/page/1
//第二类
localhost:3000/page=1

路由参数一:useParams

/page/1

对于上面的动态路由参数,我们可以使用useParams获取动态的参数

   import { useParams } from "react-router-dom"
   const params = useParams()
   console.log(params)
   

App.js

import { Routes,Route } from "react-router-dom";
import Home from "./views/Home"
import Header from "./views/Header"
import Footer from "./views/Footer"
function App() {
  return (
    <Routes> 
      <Route path="/header/:id" element={<Header></Header>}></Route>
    </Routes>
  );
}

export default App;

Header.js

import { useParams } from "react-router-dom"
export default function Header() {
  const params = useParams()
  console.log(params.id)
  return <div>
    header
  </div>
}

页面效果

5.gif

路由参数二:useSearchParams

/page?name=dzp&age=22

对于这种路由参数的设置和获取我们可以通过useSearchParams来实现

使用

   import { useSearchParams } from "react-router-dom"
   const [params, setParams] = useSearchParams()
   //获取参数
   console.log(params.get('传递的key')
   
   //设置参数
   setParams({
       key1:value1
       key2:value2
   })

Footer.js

import { useSearchParams } from "react-router-dom"
export default function Footer() {
  //第一个参数获取路由参数,第二个参数用于设置路由参数
  const [params, setParams] = useSearchParams()
  console.log(params.get('name'),params.get('age'))

  const setObj = () => {
    //设置路由参数
    setParams({
      name: "mingming",
      age:100
    })
  }
  return <div>
    footer
    <div onClick={setObj}>设置参数</div>
  </div>
}

页面效果

6.gif

4.路由其他信息(pathname,url,search等)

useLocation

useLocation可以获取当前路由的许多配置信息,常用的如下

  1. pathname:路由配置项对应的path(十分常用)

  2. search:(url搜索)

  3. hash

     //127.0.0.1:3000/login?name=dzp
     import { memo,useState,useContext } from "react";
     import { useLocation } from "react-router-dom";
     const Login: React.FC = () => {
         const location = useLocation();
         console.log(location.pathname);///login
         return (
             <div className={styles.input}>
                 login
             </div>
         )
    
     }
    

export default memo(Login);

5.嵌套路由:Outlet

嵌套路由的设计和vue一模一样,就是换了个组件名称而已。使用Outlet来放置嵌套子路由的位置

嵌套路由定义和使用

直接在需要嵌套的路由route内部继续写子路由就可以

App.js:路由定义

import { Routes,Route } from "react-router-dom";
import Home from "./views/Home"
import Child1 from "./views/Child1"
import Child2 from "./views/Child2"
function App() {
  return (
    <Routes>
      <Route path="father" element={<Home></Home>}>
        <Route path="child1" element={<Child1 />}></Route>
        <Route path="child2" element={<Child2/>}></Route>
      </Route>
    </Routes>
  );
}

export default App;

Home.js

使用Outlet作为占位符给子组件提供位置

import { Outlet } from "react-router-dom";
export default function Child1() {
  return <div>
      home
      <Outlet/>
  </div>
}

Child1.js

export default function Child1() {
  return <div>child1</div>
}

Child2.js

  export default function Child2() {
      return <div>child2</div>
 }
 

页面效果

7.gif

6.路由统一管理与懒加载

router6版本的路由统一管理是十分十分便捷的,不同于router5需要安装单独的配置路由依赖,router6可以直接将所有的路由进行集中式管理。

6.1 第一种:useRouter管理

1. 新建router/index.js

import Home from "./../views/Home"
import Page1 from "../views/Page1"
import Page2 from "../views/Page2"
import Son from "../views/Son"
export default [
  {
    path:"/",
    element:<Home/>,
    children:[
      {
        path:"son",
        element:<Son/>
      }
    ]
  },
  {
    path:"/page1",
    element:<Page1/>
  },
  {
    path:"/page2",
    element:<Page2/>
  }
]

2. app.js

直接使用useRoutes导出路由项

import router from "./router/index"
import {useRoutes} from "react-router-dom"
function App() {
  return useRoutes(router)
}

export default App;

3.页面效果

1.gif

4. 页面懒加载配置

当我们首次进入页面时,默认会加载所有的路由,因此会加剧首页的负担,可能存在首页白屏问题。基于此,我们往往需要对部分组件采取懒加载的方式实现性能优化。

改造后的路由配置

导入Suspense,lazy完成路由的懒加载配置

import { Suspense,lazy } from "react"
const Home = lazy(()=>import("./../views/Home"))
const Page1 = lazy(()=>import("./../views/Page1"))
const Page2 = lazy(()=>import("./../views/Page2"))
const Son = lazy(()=>import("./../views/Son"))

//懒加载配置处理
const lazyLoad = e => {
  return <Suspense fallback={<div>loading...</div>}>{e}</Suspense>
}
export default [
  {
    path:"/",
    element:lazyLoad(<Home/>),
    children:[
      {
        path:"son",
        element:lazyLoad(<Son/>)
      }
    ]
  },
  {
    path:"/page1",
    element:lazyLoad(<Page1/>)
  },
  {
    path:"/page2",
    element:lazyLoad(<Page2/>)
  }
]

6.2 Router与Route管理

route/index.js

import Home from "./../views/Home"
import Page1 from "../views/Page1"
import Page2 from "../views/Page2"
import Son from "../views/Son"
export default [
  {
    path:"/",
    element:<Home/>,
    children:[
      {
        path:"son",
        element:<Son/>
      }
    ]
  },
  {
    path:"/page1",
    element:<Page1/>
  },
  {
    path:"/page2",
    element:<Page2/>
  }
]

App.js

遍历router数组生成Router和Route组件

import routes from "./route/index.js"
export default function App(){
    return (
       <Routes>
        { routes.map(item=>
          <Route path={item.path} element={item.element}>
            {item.children && item.children.map(itm=>(
              <Route path={itm.path} element={itm.element}></Route>
            ))}
          </Route>
        )}
       </Routes>
    )
}

6.3 RouterProvider方式

index.js入口文件

import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import "./index.css";
const root = ReactDOM.createRoot(
  document.getElementById("root") as HTMLElement
);
root.render(
    <App />
);

App.js

import React from 'react';
import { RouterProvider  } from 'react-router-dom';
import routes from "./router"
function App() {
  return (
    <RouterProvider router={routes}></RouterProvider>
  )  
}
export default App;

router/index.js

import React, { ReactElement, createElement } from "react";
import Page1 from "./../views/Page1";
import Page2 from "./../views/Page2";
import Login from "./../views/Login";
import NotFound from "./../views/404";
import Son1 from "./../views/Son1";
import BeforeEnter from "./BeforeEnter";
import { createBrowserRouter } from "react-router-dom";

export const routes = [
  {
    path: "/",
    element: Page1,
    meta:{
      isCheck:true
    },
    children: [
      {
        path: "/son1",
        element: Son1,
        meta:{
          isCheck:true
        },
      },
    ],
  },
  {
    path: "/page2",
    element: Page2,
    meta: {
      isCheck:true
    },
  },
  {
    path: "/login",
    element:Login,
  },
  {
    path: "*",
    element: NotFound,
  },
];
export default createBrowserRouter(routes);

总结

以上我对React router 6的总结,希望伙伴们动动小手点个赞,谢谢。