React 路由 react-router-dom

詹甫
2023-12-01

React 路由 react-router-dom

  • 一个路由就是一个映射关系(key:value)
  • key为路径,value是component
  • 路由的实现是基于history

BrowserRouter和HashRouter

监听 URL 的变化,当 URL 变更时,它将使浏览器显示相应的页面

所以需要包裹在需要使用组件路由的最外层

import ReactDOM from 'react-dom';
import { BrowserRouter, Route, Routes, Link } from 'react-router-dom'
function App() {
  return (
    // 1.最外层必须使用BrowserRouter或者HashRouter包裹,
    <BrowserRouter>
      ...
    </BrowserRouter>
  );
}

HashRouter

  • 使用window.location.hash 属性和window.onhashchange事件

  • 可以监听浏览器hash值得变化,去执行相应的js切换网页

hash路由实现原理:

  1. hash 指的是地址中 # 号以及后面的字符,称为散列值

  2. 散列值不会随请求发送到服务器端的,所以改变hash,不会重新加载界面

  3. 监听onhashchange事件,hash改变时,可以通过window.location.hash来获取和设置hash值

  4. location.hash值的变化直接反应在浏览器的地址栏

BrowserRouter

  • 使用history首先应该了解window.history对象

  • 它表示的是当前窗口的浏览历史,当发生改变时,只会改变路径,不会刷新界面

  • History对象就是一个堆栈

Link 普通导航组件

<Link to="/login">....</Link>

NavLink 导航高亮组件

高亮

默认类名

点击之后,会显示高亮,高亮的默认类名是active,我们只需要编写一个类名为active的css样式即可

.active {
    background-color:red;
}

特定类名

如果高亮的类名不是active,则需要使用<NavLink to='xx' className={函数}>这种写法

  function computedClassName({ isActive }) {
     // setActives表示高亮的类名,也就是选中的样式,normal表示未选中的样式
     // isActive为true则表示选中
    return isActive ? 'setActives' : 'normal'
  }
<NavLink to='/login' className={computedClassName}>login组件</NavLink>

跳转

<a></a>跳转依靠的是href属性

NavLink跳转依靠的是to属性

Navigate 重定向组键

作用:只要<Navigate>组件被渲染,就会修改路径,切换视图

  1. 语法<Navigate to='/路径'/>
  2. <Navigate replace>replace表示跳转模式,默认是false,表示push,如果为true,表示replace
import ReactDOM from 'react-dom';
import { BrowserRouter, Route, Routes, Navigate } from 'react-router-dom'
function App() {
  return (
    <BrowserRouter>
      <Routes>
        {/* 一开始进入页面路径是'/',我们重定向到/home页面 */}
        <Route path='/' element={<Navigate to='/home' />} />
        <Route path='/home' element={<Home />} />
      </Routes>
    </BrowserRouter>
  );
}
function Home() {
  return <div>home组件</div>
}
ReactDOM.render(<App />, document.getElementById('root'))

Routes和Route

<Routes>
    <Route path='/login' element={<Login/>} />
    <Route path='/home' element={<Home />} />
</Routes>
  • <Route>组件必须被<Routes>组件包裹

  • <Routes>内匹配到一个<Route>之后,就不会继续向下匹配了

  • <Route caseSensitive>属性用于指定:匹配是否区分大小写(默认为false)

其实在实际开发中,我们如果总是用这种写法 <Routes><Route path='/Home' element={<Home />} /></Routes>进行开发

每次使用Route都要包裹一个Routes是比较麻烦的,因此就有了我们的路由表useRoutes()

路由表

我们使用路由表对路由进行统一管理

一般在src文件夹下创建routes文件夹,并在其中编写路由

语法:const element=useRoutes([{path:'路径',element:'组件',children:'子路由'}])

例子:

// 路由表
import About from '../page/About'
import Home from '../pages/Home'

export default [
    {
        path:'/about',
        element:<About/>
    },{
        path:'/home',
        element:<Home/>
    }
]
import {useRoutes} from 'react-router-dom'
import routes from './routes'

// 路由表的使用
function App(){
    const element = UseRoutes(routes)
    return (
    	{element}
    )
}

嵌套路由

子路由不用写全路径

比如:

父路由:/home

子路由:/home/news/home/messages

path:'/home',
element:<Home/>,
children:[
    {
        path:'new',
        element:<news/>
    },{
        path:'messages',
        element:<messages/>
    }
]
import ReactDOM from 'react-dom';
import { BrowserRouter, Link, useRoutes, Navigate, Outlet } from 'react-router-dom'
function App() {
  const element = useRoutes([
    {
      path: '/home', element: <Home />, children: [
        {
          path: 'news', 
          element: <News />
        }
      ]
    },
    { path: '/', element: <Navigate to='/home' /> },
  ])
  // 在路由区直接使用{element},不需要写`<Routes><Route></Route></Routes>`
  return  <div>{ element }</div> 
}
function Home() {
  return <div>home组件
    <Link to='news'>跳转到new组件</Link>
    {/* 因为是home的子组件,所以在这里使用<Outlet>组件, */}
    <Outlet />
  </div>
}
function News() {
  return <div>news组件</div>
}
ReactDOM.render(<BrowserRouter><App /></BrowserRouter>, document.getElementById('root'))

路由的params参数

  1. 路由添加占位符

    path:'detail/:id/:title/:content'
    
  2. 跳转传递参数

    <Link to={`detail/${id}/${title}/${content}`}></Link>
    
  3. 接收参数

    import {useParams} from 'react-router-dom'
    
    function Detail(){
        const {id,title,content} = useParams()
        return (
        	<ul>
            	<li>{id}</li>
                <li>{title}</li>
                <li>{content}</li>
            </ul>
        )
    }
    

路由的search参数

  1. 路由跳转传递参数

    <Link to={`detail?id=${id}&title=${title}&content=${content}`}></Link>
    
  2. 接收参数

    import {useSearchParams} from 'react-router-dom'
    function Detail(){
        const [search,setSearch] = useSearchParams()
        // 获取参数
        const id = search.get('id')
        const title = search.get('title')
    }
    

    setSearch用于修改传递的参数,使用得较少

    <button onClick={() => setSearch('id=465&title=哈哈&content=呵呵')}>更新</button>
    

路由的state参数

  1. 传递参数

    <Link 
        to="detail"
        state={{
            id:m.id,
    		title:m.title,
    		content:m.content
        }}
        ></Link>
    
  2. 接收参数

    import {useLocation} from 'react-router-dom'
    const {state:{id,title,content}} = useLocation()
    

编程式路由导航

useNavigate

  1. const navigate = useNavigate();

  2. navigate('/跳转路径',{replace:跳转模式(push或者replace,默认是push),state:{参数}})

  3. navigate(-1):后退一步,navigate(1):前进一步

import ReactDOM from 'react-dom';
import { BrowserRouter,  useRoutes, Navigate,useNavigate } from 'react-router-dom'
function App() {
  const element = useRoutes([
    { path: '/home', element: <Home /> },
    { path: '/news', element: <News /> },
    { path: '/', element: <Navigate to='/home' /> },
  ])
  return <div>{element}</div>
}
function Home() {
  const navigate=useNavigate()
  function handleClick(){
    navigate('/news')
  }
  return <button onClick={handleClick}>跳转到new组件</button>
}
function News() {
  return <div>news组件</div>
}
ReactDOM.render(<BrowserRouter><App /></BrowserRouter>, document.getElementById('root'))

 类似资料: