react-router@6 学习概览

320 阅读5分钟

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

react-router@6 打通学习
1. HashRouterBrowserRouter的区别
概述
HashRouter
在路径中包含了#,相当于HTML的锚点定位。(# 符号的英文叫hash,所以叫HashRouter)

BrowserRouter

使用的是HTML5的新特性History,没有HashRouter(锚点定位)那样通用,低版本浏览器可能不支持。
用法的却别
BrowserRouter进行组件跳转时可以传递任意参数实现组件间的通信
HashRouter不能(除非手动拼接URL字符串),因此一般配合Redux使用,实现组件间的数据通信。

HashRouter

1. HashRouter相当于锚点定位,因此不论#后面的路径怎么变化,请求的都相当于是#之前的那个页面。
可以很容易的进行前后端不分离的部署(也就是把前端打包后的文件放到服务器端的publicstatic里),
因为请求的链接都是ip地址:端口/#/xxxx,因此请求的资源路径永远为/,相当于index.html,
而其他的后端API接口都可以正常请求,不会和/冲突,由于前后端不分离也不会产生跨域问题。
2. 缺点就是丑,路径里总有个#

BrowserRouter

1. 因为BrowserRouter模式下请求的链接都是ip地址:端口/xxxx/xxxx,
因此相当于每个URL都会访问一个不同的后端地址,如果后端没有覆盖到路由就会产生404错误。
​
2. 可以通过加入中间件解决,放在服务器端路由匹配的最后,如果前面的API接口都不匹配,
则返回index.html页面。但这样也有一些小问题,因为要求前端路由和后端路由的URL不能重复。
​
3. 比如商品列表组件叫/product/list,而请求商品列表的API也是/product/list,那么就会访问不到页面,
而是被API接口匹配到。
​
解决方法:
进行前后端分离的部署,比如前端地址ip1:端口1,后端接口地址ip2:端口2,
使用Nginx反向代理服务器进行请求分发。
前端向后端发起请求的URL为nginx所在的服务器+/api/xxx,通过NGINX的配置文件判断,
如果URL以api开头则转发至后端接口,否则转发至前端的地址,访问项目只需访问Nginx服务器即可。

参考文章

2. Routes and Route
1. <Routes> and <Route> are the primary ways to render something in React

2. Router based on the current location,Whenever the location changes,
<Routes> looks through all its children <Route> elements to find the best match and 
renders that branch of the UI.
// App.tsx
import { Routes, Route } from 'react-router-dom'
import React, { Component } from 'react'const AboutPage = () => {
    return (
        <div 
            style={{ 
                width: '200px',
                height: '200px;', 
                textAlign: 'center', 
                padding: '10px' 
            }}
        >
            <div 
                style={{ 
                    background: '#ccc', 
                        marginBottom: '20px' 
                }}
            >
                react-router@6 落地
            </div>
            <Outlet />
        </div>
    )
}
const DetailPage = () => {
    return <div>详情</div>
}
const DataList = () => {
    return <div>列表</div>
}
​
const App = () => {
    return (
        <HashRouter>
            <Routes>
                <Route path="/" element={<AboutPage />}>
                    <Route path="detail" element={<DetailPage />} />
                    <Route path="list" element={<DataList />} />
                </Route>
            </Routes>
        </HashRouter>
    )
}

get.gif

如你所见,简而言之:Route根据当前路由的变化渲染不同的组件,必须要被Routes包裹

如果需要配置动态路由
 <Routes>
    <Route path="/" element={<AboutPage />}>
        <Route path="detail">
            <Route path=":id" element={<DetailPage />} />
        </Route>
        <Route path="list" element={<DataList />} />
    </Route>
</Routes>

test2.gif

默认路由
 <Routes>
    <Route path="/" element={<AboutPage />}>
        <Route index element={<DataIndex />} />
        <Route path="detail">
            <Route path=":id" element={<DetailPage />} />
        </Route>
        <Route path="list" element={<DataList />} />
    </Route>
</Routes>

mulget.gif

在嵌套路由中,如果 URL 仅匹配了父级 URL,则Outlet中会显示带有index属性的子路由。

3. Outlet
An <Outlet> should be used in parent route elements to render their child route elements.

如上面的实例 可以看出:

Outlet组件,用于父组件中可以为子路由的元素占位,并最终渲染子路由的元素。

4. Navigate
A <Navigate> element changes the current location when it is rendered.

页面重定向等价于以前版本中的Redirect组件

const DetailPage = () => {
    return <div>详情</div>
}
const DataList = () => {
    return <div>列表</div>
}
const DataIndex = () => {
    return <Navigate to="list" replace={true} />
}
​
const App = () => {
    return (
        <HashRouter>
            <Routes>
                <Route path="/" element={<AboutPage />}>
                    <Route index element={<DataIndex />} />
                    <Route path="detail">
                        <Route path=":id" element={<DetailPage />} />
                    </Route>
                    <Route path="list" element={<DataList />} />
                </Route>
            </Routes>
        </HashRouter>
    )
}

redirect.gif

5. Link
A <Link> is an element that lets the user navigate to another page by clicking or tapping on it.
const DetailPage = () => {
    return <div>详情</div>
}
const DataList = () => {
    return <div>列表</div>
}
const DataIndex = () => {
    return (
        <div>
            <div>
                <Link to="list">去列表</Link>
            </div>
            <div>
                <Link to="detail/1">详情</Link>
            </div>
        </div>
    )
}
const App = () => {
    return (
        <HashRouter>
            <Routes>
                <Route path="/" element={<AboutPage />}>
                    <Route index element={<DataIndex />} />
                    <Route path="detail">
                        <Route path=":id" element={<DetailPage />} />
                    </Route>
                    <Route path="list" element={<DataList />} />
                </Route>
            </Routes>
        </HashRouter>
    )
}

link.gif

6. NavLink
A <NavLink> is a special kind of <Link> that knows whether or not it is "active". 
This is useful when building a navigation menu such as a breadcrumb or a set of tabs 
where you'd like to show which of them is currently selected. 
const AboutPage = () => {
    return (
        <div 
            style={{ 
                width: '200px', 
                height: '200px', 
                textAlign: 'center', 
                padding: '10px' }}
       >
            <div style={{ 
                    background: '#ccc', 
                    marginBottom: '20px' 
                }}
            >
                react-router@6 落地
           </div>
            <NavLink 
                to="list" 
                style={({ isActive }) => ({ 
                    color: isActive ? 'red' : 'blue' 
                })}
            >
                list
            </NavLink>
            <span style={{ marginLeft: '40px' }}>
                <NavLink
                    to="detail/1"
                    style={({ isActive }) => ({ 
                        color: isActive ? 'red' : 'blue' })}
                >
                    detail
                </NavLink>
            </span>
            <Outlet />
        </div>
    )
}
​
const DetailPage = () => {
    return <div>详情</div>
}
const DataList = () => {
    return <div>列表</div>
}
const DataIndex = () => {
    return (
        <div>
            <div>
                <Link to="list">去列表</Link>
            </div>
            <div>
                <Link to="detail/1">详情</Link>
            </div>
        </div>
    )
}
const App = () => {
    return (
        <HashRouter>
            <Routes>
                <Route path="/" element={<AboutPage />}>
                    <Route index element={<DataIndex />} />
                    <Route path="detail">
                        <Route path=":id" element={<DetailPage />} />
                    </Route>
                    <Route path="list" element={<DataList />} />
                </Route>
            </Routes>
        </HashRouter>
    )
}

color.gif

7. 路由js 跳转

根据ajax请求返回值跳转不同的页面,这时我们就得使用js的方式时行跳转了,虽然新版的react-router已经移除掉history对象,但给我们提供了 useNavigate() hook实现路由跳转,

import { useNavigate } from "react-router-dom";
let navigate = useNavigate();
navigate(`/home`);
​
// 跳转且不保留浏览记录
navigate(`/home`,{replace:true});
​
// 返回上一页
navigate(-1)
​
// 对象方式跳转
navigate({
    pathname:'/home'
})
​
​

需要注意一点就是,在v6版本的react-router中,如果跳转的路径如果不是以/开头,则为相对路径,相对于其父级路由路径,这样的设置能让我们更好的控制跳转

路由传参

在进行路由跳转时,可以通过附带一些参数一起传递到目标页面来实现某些特殊功能,但新版的react-router已经从props中移除了historylocationmatch,也移除掉了withRouter高阶组件,所以无法使用老版本的方式传参与接收,新版用法如下:

search传参

import { useNavigate } from "react-router-dom";
let navigate = useNavigate();
navigate(`/home?pageIndex=1&pageSize=10`);
navigate({
    pathname:'/home',
    search:'pageIndex=1&pageSize=10'
});
​

接受参数

在对应组件接收参数,使用useSearchParams hook进行接收,得到URLSearchParams对象以及设置search参数函数组成的数据

function Home(){
    const [searchParams,setSearchParams] = useSearchParams()
    searchParams.get('pageIndex'); // 1
    searchParams.get('pageSize'); // 10
    return (
        <div>首页</div>
    )
}