升级!react-router V5到react-router V6----结合项目

千锋前端-React全家桶_React项目实战全球新闻发布管理系统_哔哩哔哩_bilibili

该项目的路由部分是用react-router V5写的,但是react的路由目前已经更新到V6版本,因此将项目中的路由部分更新了一下。主要包括如下几个方面:

一. <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> 组件
来渲染其子路由。
结合项目:
V5版本:
export default function IndexRouter() {
    return (
        <HashRouter>
            <Switch>
                {/* login,news,detail,/这四个可以拿到路由组件提供的props,但是NewsSandBox拿不到 */}
                <Route path="/login" component={Login} />
                {/* 下面这两个是作为游客身份登陆时可以访问到的组件 */}
                <Route path="/news" component={News} />
                <Route path="/detail/:id" component={Detail} />
                {/* <Route path="/" component={NewsSandBox}/> */}
            </Switch>
        </HashRouter>
    )
}
V6版本:
export default function IndexRouter() {
    return (
        <HashRouter>
            {/* react-route V6版本中HashRouter 里面包 Switch 会出错,改为包 Routes (Routes 和 Switch 的功用是一样的,都能做到精准匹配) */}
            <Routes>
                {/* Route 的 component 属性改为 element,并且 element 中使用 <> 包裹组件名称 */}
                <Route path="/login" element={<Login />} />
                {/* 下面这两个是作为游客身份登陆时可以访问到的组件 */}
                <Route path="/news" element={<News />} />
                <Route path="/detail/:id" element={<Detail />} />
                {/* <Route path="/" component={NewsSandBox}/> */}
            </Routes>
        </HashRouter>
    )
}

二. 重定向Navigate

1. 作用:只要 <Navigate> 组件被渲染,就会修改路径,切换视图。
2. replace 属性用于控制跳转模式( push replace ,默认是 push )。
结合项目:
V5版本:
                <Route path="/" render={() =>
                    localStorage.getItem("token") ?
                        <NewsSandBox ></NewsSandBox> :
                        <Redirect to="/login" />
                } />
V6版本:
import { Navigate } from 'react-router-dom'
// ...
                <Route path="/" element={
                    localStorage.getItem("token") ?
                        <NewsSandBox ></NewsSandBox> :
                        // 重定向时需要将 Redirect 改为 Navigate,并且一样使用的是 element 而不是 render
                        <Navigate to="/login" />
                } />

三. 废除withrouter,使用Hooks

1. useNavigate()

作用:返回一个函数用来实现编程式导航。结合项目:

V5版本:

function SideMenu(props) {
  // 使用withroute高阶组件,使该组件可以接受到路由组件传来的props属性
  // 获取当前url中的key值,传入Menu中,作为选中/展开条件
  ....
  ....
  const renderMenu = (menuList) => {
    ....
      return checkPagePermission(item) && <Menu.Item key={item.key} icon={iconList[item.key]} onClick={() => {
        props.history.push(item.key)
      }}>{item.title}</Menu.Item>
    })
  }
  const selectKeys = [props.location.pathname]
  const openKeys = ["/" + props.location.pathname.split("/")[1]]
  return (
   ....
}
export default connect(mapStateToProps)(withRouter(SideMenu))

V6版本:

import { useNavigate, useLocation } from "react-router";
function SideMenu(props) {
  let navigate = useNavigate();
  ......
  ......
  const renderMenu = (menuList) => {
    ......
      return checkPagePermission(item) && <Menu.Item key={item.key} icon={iconList[item.key]} onClick={() => {
        navigate(item.key)
      }}>{item.title}</Menu.Item>
    })
  }
  // V6写法
  let location = useLocation();
  const selectKeys = [location.pathname];
  const openKeys = ["/" + location.pathname.split("/")[1]];
  return (
   .......
  )
}

2. useParams

1. 作用:回当前匹配路由的 params 参数,类似于 5.x 中的 match.params 。项目中对比:
V5版本:
 const [newsInfo, setnewsInfo] = useState(null)
    useEffect(() => {
        axios.get(`/news/${props.match.params.id}?_expand=category&_expand=role`).then(res => {
            setnewsInfo({
                ...res.data,
                // 每刷新一次就把view的值加一
                view: res.data.view + 1
            })
            //同步后端
            return res.data
        }).then(res => {
            axios.patch(`/news/${props.match.params.id}`, {
                view: res.view + 1
            })
        })
    }, [props.match.params.id])
    const handleStar = () => {
        // 本地和数据库都要更新数据
        setnewsInfo({
            ...newsInfo,
            star: newsInfo.star + 1
        })
        axios.patch(`/news/${props.match.params.id}`, {
            star: newsInfo.star + 1
        })
    }
V6版本:
import { useParams } from "react-router";
const params = useParams();
const [refresh, setRefresh] = useState(false);
export default function Detail(props) {
    const [newsInfo, setnewsInfo] = useState(null)
    let star = localStorage.getItem("star") || [];
    useEffect(() => {
        axios.get(`/news/${params.id}?_expand=category&_expand=role`).then(res => {
            setnewsInfo({
                ...res.data,
                // 每刷新一次就把view的值加一
                view: res.data.view + 1
            })
            //同步后端
            return res.data
        }).then(res => {
            axios.patch(`/news/${params.id}`, {
                view: res.view + 1
            })
        })
    }, [refresh])
    const handleStar = () => {
        if (!star.includes(params.id.toString())) {
            updateNews(params.id, {
                star: newsInfo.star + 1,
            })
                .then(() => {
                    setRefresh();
                    const arr = [...star];
                    localStorage.setItem("star", arr.concat(params.id));
                })
                .catch((e) => console.log(e));
        } else {
            notification.info({
                message: `error`,
                description: `starError`,
                placement: "bottomRight",
            });
        }
    };
    ......
}

四. 其它

1. useRoutes()

1. 作用:根据路由表,动态创建 <Routes> <Route>
2. 示例代码:
//路由表配置:src/routes/index.js 
import About from '../pages/About'
import Home from '../pages/Home' 
import {Navigate} from 'react-router-dom'
export default [ 
    { path:'/about', element:<About/> },
    { path:'/home', element:<Home/> },
    { path:'/', element:<Navigate to="/about"/> } 
]
//App.jsx 
import React from 'react' 
import {NavLink,useRoutes} from 'react-router-dom' 
import routes from './routes' 
export default function App() { 
    //根据路由表生成对应的路由规则 
    const element = useRoutes(routes) 
    return (
         <div>...... 
        {/* 注册路由 */} 
        {element} ...... 
        </div> ) 
}

2. useLocation()

1. 作用:获取当前 location 信息,对标 5.x 中的路由组件的 location 属性。
2. 示例代码:
import React from 'react' 
import {useLocation} from 'react-router-dom' 
export default function Detail() { 
    const x = useLocation() 
    console.log('@',x) // x就是location对象:
    /* { 
    hash: "", 
    key: "ah9nv6sz", 
    pathname: "/login", 
    search: "?name=zs&age=18", 
    state: {a: 1, b: 2} 
    }*/
    return ( 
        <ul>
            <li>消息编号:{id}</li> 
            <li>消息标题:{title}</li> 
            <li>消息内容:{content}</li> 
        </ul> ) 
}

3. useMatch()

1. 作用:返回当前匹配信息,对标 5.x 中的路由组件的 match 属性。
2. 示例代码:
<Route path="/login/:page/:pageSize" element={<Login />}/>
<NavLink to="/login/1/10">登录</NavLink>
export default function Login() { 
const match = useMatch('/login/:x/:y') 
console.log(match) //输出match对象 
//match对象内容如下: /*
{ 
    params: {x: '1', y: '10'} 
    pathname: "/LoGin/1/10" pathnameBase: "/LoGin/1/10" 
    pattern: { path: '/login/:x/:y',
    caseSensitive: false, 
    end: false } 
} */
    return ( 
    <div> 
        <h1>Login</h1> 
    </div> 
    ) 
}

4. useInRouterContext()

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

5. useNavigationType()

1. 作用:返回当前的导航类型(用户是如何来到当前页面的)。
2. 返回值: POP PUSH REPLACE
3. 备注: POP 是指在浏览器中直接打开了这个路由组件(刷新页面)。

6. useOutlet()

1. 作用:用来呈现当前组件中渲染的嵌套路由。
2. 示例代码:
const result = useOutlet() 
console.log(result) 
// 如果嵌套路由没有挂载,则result为null 
// 如果嵌套路由已经挂载,则展示嵌套的路由对象

7. useResolvedPath

1. 作用:给定一个 URL 值,解析其中的: path search hash 值。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值