react router 6,嵌套路由、重定向、路由传参、编程式导航

-

react-router官网:https://reactrouter.com/

2021年11月 react router 6 成为默认版本,npm安装时自动安装6版本

每次react router发布都会有3个版本

react-router : 路由的核心库,提供了很多组件钩子

react-router-dom: 包含react-douter所有内容,并添加了一些专门用于DOM的组件,例如BrowserRouter

react-router-native: 包含react-douter所有内容,并添加了一些专门用于ReactNative的一些api,例如Nativerouter

 

react router 6版本与5版本有哪些改动

1、内置组件的变化:移除<Switch> 新增Routers等

2、语法的变化:component={About} 变成 element={<About />}

3、新增多个hook:useParams、useNavigate、useMatch

4、官方声明推荐函数式组件

 

一、路由模式选者

首先在入口文件index.js用BrowserRouter把App组件包裹住,代表用的是BrowserRouter,还有一种模式是hashRouter

index.js

import React from 'react'
import ReactDOM from 'react-dom/client'
import { BrowserRouter } from 'react-router-dom'
import App from './App'

const root = ReactDOM.createRoot(document.getElementById('root'));

root.render(
  <BrowserRouter>
    <App/>
  </BrowserRouter>
)

 二、一级路由 ----- 路由的基本使用 NavLink 、 Link、Routes、 Route

Route必须由Routes包裹住,不包裹会报错,原来的Switch包裹是为了解决一直向下匹配的问题,用Routes包裹后也不存在这个问题

另外,Route的component={About}改成了 element={<About/>}

App.jsx

import React from 'react'
import { NavLink, Route, Routes } from 'react-router-dom'
import Home from './pages/Home'
import About from './pages/About'
import Demo from './pages/Demo'
import './App.css'

export default function App() {
  return (
    <div className="container">
      <h1>react-router-dom-demo</h1>
      <div className="main">
        <aside className="aside">
          { /**
           * 编写路由链接
           * 在react中,靠路由连接切换组件
           */}
            <NavLink className="btn" to="/home">home</NavLink>
            <NavLink className="btn" to="/about">about</NavLink>
        </aside>
        <div className="content">
          {/**
           * 注册路由
           */}
           <Routes>
             {/* 路由匹配住/home后,不会再往下匹配 */}
            <Route path="/home" element={<Home/>}></Route>
            <Route path="/home" element={<Demo/>}></Route>
            <Route path="/about" element={<About/>}></Route>
           </Routes>
        </div>
      </div>
    </div>
  )
}

 三、路由重定向 Navigate

当没有匹配任何路由的情况下,会有警告:No routes matched location "/" 

5版本的重定向是使用Redirect: <Redirect to="/home"></Redirect>

6版本用Navigate组件,他有以下特性:

1、这个组件只要被渲染就会更改路径,切换路由

2、有一个replace属性,默认为false,为push模式,如果为true,就是replace模式(不会留下历史记录)

使用示例:

  import { NavLink, Route, Routes, Navigate } from 'react-router-dom'
路由 / ,默认跳转到 /home路径  
<Routes>
   <Route path="/home" element={<Home/>}></Route>
   <Route path="/about" element={<About/>}></Route>
   <Route path="/" element={<Navigate to="/home"/>}></Route>
</Routes> 

以下是通过条件判断,让路由切换
{ sum === 2 ? <Navigate to="/about"></Navigate> : <div>当前sum的值是: {sum}</div>}  

四、Routes与Route

1、v6版本移除了<Switch>,用Routes替代

2、Routes和Route要配合使用,必须用Routes包裹Route

3、Route相当于if语句,如果与当前URL匹配,就呈现对应组件

4、<Route caseSensitive /> 用于指定:匹配时是否区分大小写,默认为false

5、当URL发生变化时,<Routes>都会查其所有子<Route>以找到最佳匹配并呈现其页面

6、<Route/>也可以嵌套使用,且可配合useRoutes()配置'路由表',但需要通过 <outlet>组件来渲染子路由

 五、NavLink高亮效果

5版本的NavLink高亮效果是组件内部会自动加上active类名,如果自定义高亮样式,可以加activeClassName,指定被选中的样式

6版本不支持activeClassName属性,router6要求,如果想自定义class类名,需要把className写成一个函数,返回类名

{ /**
           * 编写路由链接
           * 在react中,靠路由连接切换组件
           */}
          <NavLink className={ ({isActive}) => isActive ? 'btn route_active' : 'btn' } to="/home">home</NavLink>
          <NavLink className="btn" to="/about">about</NavLink>

 嫌写的复杂了,可以提取出一个计算属性

function computedClassName({isActive}) {
   return isActive ? 'btn route_active' : 'btn'
}

<NavLink className={ computedClassName } to="/home">home</NavLink>
<NavLink className={ computedClassName } to="/about">about</NavLink>

 六、路由表的使用---useRoutes

我们把下面这个写成一个路由表,路由表必须是个数组

 

 ===》

import { NavLink, Route, Routes, Navigate, useRoutes } from 'react-router-dom'

  const element = useRoutes([
    {
      path: '/home',
      element: <Home/>
    },
    {
      path: '/about',
      element: <About/>
    },
    {
      path: '/',
      element: <Navigate to="/home"/>
    }
  ])
  {/**
    * 注册路由
    */}
  {/* <Routes>
       <Route path="/home" element={<Home/>}></Route>
        <Route path="/ab0ut" element={<About/>}></Route>
        <Route path="/" element={<Navigate to="/home"/>}></Route>
     </Routes> */}
   取而代之
  {element}
  

 一般路由表会专门用一个文件来写

routes/index.js

import { Navigate } from 'react-router-dom'
import Home from '../pages/Home'
import About from '../pages/About'

const routes = [
  {
    path: '/home',
    element: <Home/>
  },
  {
    path: '/about',
    element: <About/>
  },
  {
    path: '/',
    element: <Navigate to="/home"/>
  }
]

export default routes

页面中引入使用:

import { NavLink, useRoutes } from 'react-router-dom'
import routes from './routes'

// 根据路由表生成对应的路由规则
const element = useRoutes(routes);

 七、嵌套路由

router6的路由表统一在routes文件下配置,那么子路由就需要一个槽位来指定子路由显示的位置,这个标签是outlet,相当于vue中的router-view,

配置嵌套路由表:

routes/index.js

import { Navigate } from 'react-router-dom'
import Home from '../pages/Home'
import About from '../pages/About'
import News from '../pages/News'
import Message from '../pages/Message'

const routes = [
  {
    path: '/home',
    element: <Home/>,
    children: [
      {
        path: 'news',
        element: <News/>
      },
      {
        path: '/home/message',
        element: <Message/>
      },
    ]
  },
  {
    path: '/about',
    element: <About/>
  },
  {
    path: '/',
    element: <Navigate to="/home"/>
  }
]

export default routes

Outlet指定子路由在页面中显示的位置:

import { Outlet  } from 'react-router-dom';

{<Outlet/>}

另外一个小知识点,当切换到子路由时,对应的父级路由也会高亮,在父级路由的NavLink上加上end属性,可以不让其高亮

<NavLink className={ computedClassName } end to="/home">home</NavLink>

 八、路由传参

 (1)、params传参:接收参数时使用useParams函数

路由表里定义params参数

   {
        path: '/home/message',
        element: <Message/>,
        children: [
          {
            path: 'detail/:id/:title/:content',
            element: <Detail/>
          }
        ]
      }

路由跳转时传入参数

          messages.map(m => {
            return <li key={m.id}>
              <Link to={`detail/${m.id}/${m.title}/${m.content}`}>{m.title}</Link>
            </li>
          })

接收路由params参数,需要用到useParams()

import { useParams } from 'react-router-dom'
const params = useParams();

也可以用useMatch()

import { useMatch } from 'react-router-dom'
const a = useMatch('/home/message/detail/:id/:title/:content');

 (2)、search传参

需要用useSearchParams()接收参数

search传参:

          messages.map(m => {
            return <li key={m.id}>
              <Link to={`detail?id=${m.id}&title=${m.title}&content=${m.content}`}>{m.title}</Link>
            </li>
          })

接收参数:useSearchParams()

import React from 'react'
import { useParams, useMatch, useSearchParams } from 'react-router-dom'

export default function Detail() {
  const [search, setSearch] = useSearchParams();
  const id = search.get('id');
  const title = search.get('title');
  const content = search.get('content');
  return (
    <ul>
      <button onClick={ () => setSearch('id=008&title=嘻嘻&content=哈哈') }>点我更改search参数</button>
      <li>id:{id}</li>
      <li>title:{title}</li>
      <li>content:{content}</li>
    </ul>
  )
}

 也可以用useLocation()接收

import { useLocation } from 'react-router-dom'
const x = useLocation();

 (3)、state传参

传参:

          messages.map(m => {
            return <li key={m.id}>
              <Link to="detail" state={{ id: m.id, title: m.title, content: m.content }}>{m.title}</Link>
            </li>
          })

接收参数,使用useLocation()

import { useLocation } from 'react-router-dom'
const {state} = useLocation();

 九、编程式导航

需要用到useNavigate()

在router5中,普通组件想使用路由里的location、match、history,需要用withRouter(组件)加工一下,但router6不需要,可以直接用钩子函数就可以使用router的任何东西

const navigate = useNavigate();

路由跳转、传参

    // search、params传参直接在路径中传参,state在第二个参数里传
    navigate('detail',{
      replace: false,
      state: {
        id:m.id,
        title:m.title,
        content:m.content,
      }
    })

前进、后退

navigate(1) // 前进
navigate(-1) // 后退

 十、useInRouterContext()

作用:如果组件在<Router>的上下文中呈现,则useInRouterContext()返回true,否则返回false

被BrowserRouter或HashRouter包裹住的就是在路由环境中

import { useInRouterContext } from 'react-router-dom'
console.log(useInRouterContext());

 十一、useNavigationType()

作用:返回当前导航类型(用户是如何来到当前页面的)

返回值:POP、PUSH、REPLACE

备注:POP是指在浏览器中直接打开这个路由组件(刷新页面)

import { useNavigationType } from 'react-router-dom'
const type = useNavigationType();

十二、useOutlet

作用:用来呈现当前组件中渲染的嵌套路由

import { useOutlet } from 'react-router-dom'
const childRoute = useOutlet();
  // 如果嵌套路由没有挂载,childRoute返回null
  // 如果嵌套路由已挂载,返回渲染的路由对象

 十三、useResolvedPath()

作用:给一个URL值,解析期中的path、search、hash

import { useResolvedPath } from 'react-router-dom'
useResolvedPath('/user?id=001&name=tom#qwe')

 

 

 

 

 

 

 

 

 

 

 

 

-

posted @ 2022-10-23 16:18  古墩古墩  Views(6482)  Comments(0Edit  收藏  举报