IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> React-router-dom 6总结 -> 正文阅读

[JavaScript知识库]React-router-dom 6总结

React-router-dom 6总结

路由传参的几种方式

  1. Search传参,类似于url中的 ?xxx=yyy&zzz=rrr

    我们一般需要用到 qs 库,用于处理查询

    import qs from 'qs';
    //将 ?xxx=yyy&zzz=rrr 截串,然后转换成对象 {xxx:yyy,zzz:rrr}
    const detail = qs.parse(search.substring(1));
    //将对象转换成search
    const str = qs.stringify(detail)
    
  2. Params 传参,需要在路由声明接受参数 类似于restful,/:id/:name/:gender

  3. state传参

    //v5 中的使用方式 to 不再是一个路由字符串,而是一个对象
    {/* 方式3:通过state传递参数,在location.state中获取,link中的to传递为一个对象,必须包含pathname与state字段属性  */}
    <Link to={{ pathname: '/home/message/detail', state: message }}>{message.title}</Link>
    

V6的注意点

  1. 移除了 标签,使用标签替代

  2. 引入了useRoutes([])用于根据路由表创建根路由,其返回值是dom,用{}包裹,放置于节点下即可配置全部一级路由

  3. 路由表的创建模式

    // import About from "../pages/About";
    // import Home from "../pages/Home";
    import News from "../pages/Home/News";
    import Message from "../pages/Home/Message";
    import { Navigate } from "react-router-dom";
    import Detail from "../pages/Home/Message/Detail";
    import { lazy } from "react";
    
    const About = lazy(() => import("../pages/About"));
    const Home = lazy(() => import("../pages/Home"));
    
    export const routes = [
      { path: "/", element: <Navigate to={"/a/about"} /> },
      { path: "/a/about", element: <About /> },
      {
        path: "/home",
        element: <Home />,
        children: [
          //如果称`/`为根路由,那么`/home`就是一级子路由,`/home/news`就是二级子路由,我们希望打开home时帮我们导航到news
          //既可以在children中写一个空字符串的二级子路由,并将它通过Navigate的to属性指定为`/home/news`,就可以实现
          { path: "", element: <Navigate to={"news"} /> },
          { path: "news", element: <News /> },
          {
            path: "message",
            element: <Message />,
            children: [
              //使用search传参,或者state传参
              {
                path: "detail",
                element: <Detail />,
              },
              //使用params传参
              //   {
              //     path: "detail/:id/:title",
              //     element: <Detail />,
              //   },
            ],
          },
        ],
      },
    ];
    
    
  4. 子组件不需要再使用钩子创建路由,路由框架通过识别子组件的 以及路由表的children关系,可以知道往什么地方渲染子组件,这一点非常方便

  5. 标签取消了 activeClassName ,className可以赋值一个函数,系统会为该函数传递一个{isActive:true}的对象作为参数;

  6. 在@5中的几个钩子大多数废弃,例如:useHistoryuseRouteMatch()已经废弃或移除,useLocation保留,新增加了useParams,非常好用,state传参与params传参都有简化

  7. 我们无法再获取useHistory钩子再获取history对象,但是可以使用useNavigate钩子获取navigate对象,在使用navigate对象导航时也与history不同:

    const nav = useNavigate()
    //此处可以不写全路径,只写子路由也可以成功导航
    nav(`/home/message/detail`, { replace: true, state: message })
    //傻瓜式前进后退
    nav(-1)
    nav(1)
    

    nav函数的参数二接受的是一个固定类型的对象,不要随便传(TS在工程化的必要性?)

  8. 我们依旧可以使用React提供的lazy函数,只不过现在需要在路由表中声明

    // import About from "../pages/About";
    // import Home from "../pages/Home";
    import News from "../pages/Home/News";
    import Message from "../pages/Home/Message";
    import { Navigate } from "react-router-dom";
    import Detail from "../pages/Home/Message/Detail";
    import { lazy } from "react";
    
    const About = lazy(() => import("../pages/About"));
    const Home = lazy(() => import("../pages/Home"));
    
    export const routes = [
      { path: "/", element: <Navigate to={"/a/about"} /> },
      { path: "/a/about", element: <About /> },
      {
        path: "/home",
        element: <Home />,
        children: [
          //如果称`/`为根路由,那么`/home`就是一级子路由,`/home/news`就是二级子路由,我们希望打开home时帮我们导航到news
          //既可以在children中写一个空字符串的二级子路由,并将它通过Navigate的to属性指定为`/home/news`,就可以实现
          // { path: "", element: <Navigate to={"news"} /> },
          //我们还可以直接使用index:true,配合<Navigate>标签实现默认导航
          { index: true, element: <Navigate to={"news"} /> },
          { path: "news", element: <News /> },
          {
            path: "message",
            element: <Message />,
            children: [
              //使用search传参,或者state传参
              {
                path: "detail",
                element: <Detail />,
              },
              //使用params传参
              //   {
              //     path: "detail/:id/:title",
              //     element: <Detail />,
              //   },
            ],
          },
        ],
      },
    ];
    

    Tips:不要忘记在根路由组件中使用<Suspense fallback={<h2>Loading</h2>}>{elements}</Suspense>包裹住根路由表。

  9. 新增加 end 关键字,当在上一级路由的link标签中使用end关键字,当他的下级路由被点击,他将失去激活状态。

  10. 路由鉴权,使用高阶组件包一下需要鉴权的页面,如果不能鉴权通过,则跳转,能鉴权通过则使用渲染:

    import React from 'react'
    import { Fragment } from 'react';
    import { Navigate } from 'react-router-dom';
    import useLocalStorage from '../hooks/useLocalStorage'
    
    //一个简单的鉴权操作
    export const AuthWrapComponent = ({ children }) => {
        const [token, _] = useLocalStorage('token');
        return (
            <Fragment>
                {/* 注意一定要replace ,导航到404空白页 或者 401无权*/}
                {token ? children : <Navigate to='/a/about' replace />}
            </Fragment>
        )
    }
    
    

    几个钩子的使用

    1. useLocation: 获取当前路径,state传参时可以拿到 state 对象,还可以通过 patchname 拿到当前路由路径(不包含?)
    2. useSearchParams:获取当前查询路径对象,需要使用get获取对应key的值
    3. useParams:拿到 params传参的对象

    简单的一个示例:

    const Detail = (props) => {
    
        // 方式1:通过search传递参数,比较复杂,不推荐,
        //需要用解构赋值获得search对象,然后调用get函数获取对应的key的值
        // const [search] = useSearchParams()
        // const detail = { id: search.get('id'), title: search.get('title') }
    
        // 方式2:通过params参数传递,非常简单直接使用useParams()
        // const detail = useParams()
    
        // 方式3:通过state传递参数
        // const { state: detail } = useLocation();
        // console.log("此处可以收到来自route的state参数:", detail);
      
      	//方式1+plus:自定义的钩子根据传入的key数组拿到search中的数据并包装成对象
      	const detail = useUrlQueryParam(['id', 'title'])
        console.log("获取到对象:", detail);
    
        return (
            <ul>
                <li>ID:{detail.id}</li>
                <li>TITLE:{detail.title}</li>
                <li>CONTENT:{detail.title}+{detail.id}</li>
            </ul>
        )
    }
    
    export default Detail
    
    //js下极简的封装
    export const useUrlQueryParam = (keys) => {
        const [search] = useSearchParams()
        //遍历keys,从search中获取对应的值,返回一个新对象
        const query = keys.reduce((acc, key) => {
            acc[key] = search.get(key)
            return acc
        }, {})
        return query
    }
    

    例如这样一个URL :http://localhost:3000/projects/1/kanban?id=1

    在使用两个钩子的效果:

        const { pathname } = useLocation()
        const [urlparam] = useSearchParams()
        console.log(pathname, urlparam);
    //### : /projects/1/kanban id=1
    

    可以看出他们是术业有专攻的

    在 TypeScript 下封装 useSearchParams

    由于 useSearchParams 钩子的不易用,不能直接返回我们需要的对象,我们可以自行封装如下钩子,帮助我们获取对象:

    import { useMemo, useState } from "react"
    import { URLSearchParamsInit, useSearchParams } from "react-router-dom"
    
    export const isVoid = (value: unknown) => value === undefined || value === null || value === "";
    export const isNullOrUndefined = (value: unknown) => value === undefined || value === null;
    
    //在js中函数传入对象是一个不好的方式,因为函数可能会污染对象
    export const cleanObject = (obj?: { [key: string]: unknown }) => {
      //空对象直接返回
      if (!obj) return {};
      //浅拷贝
      const result = { ...obj };
      //清除对象中的空值
      Object.keys(result).forEach((key) => {
        const value = result[key];
        if (isVoid(value)) {
          delete result[key];
        }
      });
      return result;
    };
    
    /**
     * 传入一个对象,和键集合,返回对应的对象中的键值对
     * @param obj
     * @param keys
     */
    export const subset = <O extends { [key in string]: unknown }, K extends keyof O>(obj: O, keys: K[]) => {
      const filteredEntries = Object.entries(obj).filter(([key]) =>
        keys.includes(key as K)
      );
      return Object.fromEntries(filteredEntries) as Pick<O, K>;
    };
    
    //获取查询参数 => 转换成对象
    export const useUrlQueryParam = <K extends string>(keys: K[]) => {
        const [searchParams] = useSearchParams()
        const setSearchParams = useSetUrlSearchParam()
        const [stateKeys] = useState(keys)
        return [
            useMemo(
                () => subset(Object.fromEntries(searchParams), stateKeys) as { [key in K]: string },
                [searchParams, stateKeys]
            ),
            (params: Partial<{ [key in K]: unknown }>) => setSearchParams(params)
        ] as const
    };
            
    //专门用来修改url的查询参数的钩子
    export const useSetUrlSearchParam = () => {
        const [searchParam, setSearchParam] = useSearchParams()
        return (params: Partial<{ [key in string]: unknown }>) => {
            const o = cleanObject({
                ...Object.fromEntries(searchParam),
                ...params
            }) as URLSearchParamsInit
            return setSearchParam(o)
        }
    };
    
    
    ----------
    
    //使用:
    const [param, setParam] = useUrlQueryParam(['name', 'personId'])
    
  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-07-03 10:40:34  更:2022-07-03 10:43:01 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年1日历 -2025/1/11 10:08:00-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码