【实战】 七、Hook,路由,与 URL 状态管理(下) —— React17+React Hook+TS4 最佳实践,仿 Jira 企业级项目(十三)

文章目录

    • 一、项目起航:项目初始化与配置
    • [二、React 与 Hook 应用:实现项目列表](#二、React 与 Hook 应用:实现项目列表)
    • [三、TS 应用:JS神助攻 - 强类型](#三、TS 应用:JS神助攻 - 强类型)
    • 四、JWT、用户认证与异步请求
    • [五、CSS 其实很简单 - 用 CSS-in-JS 添加样式](#五、CSS 其实很简单 - 用 CSS-in-JS 添加样式)
    • [六、用户体验优化 - 加载中和错误状态处理](#六、用户体验优化 - 加载中和错误状态处理)
    • [七、Hook,路由,与 URL 状态管理](#七、Hook,路由,与 URL 状态管理)
      • 1+2.
      • 3~6
      • [7.完成URL状态管理与JS中的 iterator讲解](#7.完成URL状态管理与JS中的 iterator讲解)

学习内容来源:React + React Hook + TS 最佳实践-慕课网


相对原教程,我在学习开始时(2023.03)采用的是当前最新版本:

版本
react & react-dom ^18.2.0
react-router & react-router-dom ^6.11.2
antd ^4.24.8
@commitlint/cli & @commitlint/config-conventional ^17.4.4
eslint-config-prettier ^8.6.0
husky ^8.0.3
lint-staged ^13.1.2
prettier 2.8.4
json-server 0.17.2
craco-less ^2.0.0
@craco/craco ^7.1.0
qs ^6.11.0
dayjs ^1.11.7
react-helmet ^6.1.0
@types/react-helmet ^6.1.6
react-query ^6.1.0
@welldone-software/why-did-you-render ^7.0.1
@emotion/react & @emotion/styled ^11.10.6

具体配置、操作和内容会有差异,"坑"也会有所不同。。。


一、项目起航:项目初始化与配置

二、React 与 Hook 应用:实现项目列表

三、TS 应用:JS神助攻 - 强类型

四、JWT、用户认证与异步请求


五、CSS 其实很简单 - 用 CSS-in-JS 添加样式


六、用户体验优化 - 加载中和错误状态处理



七、Hook,路由,与 URL 状态管理

1+2.

3~6

7.完成URL状态管理与JS中的 iterator讲解

searchParams 拿到了, 接下来用暴露出来的 setSearchParams 来替换 ProjectList 里的 setParam

修改 src\screens\ProjectList\index.tsx

js 复制代码
...
export const ProjectList = () => {
  const [param, setParam] = useUrlQueryParam(["name", "personId"]);
  ...
};
...

但是这样使用 setParam 时若是传入一个 { name1: 'Jack' } 的参数,没有任何报错拦截,这样肯定是不行的,所以需要在 setParamsetSearchParams 中使用对 key 的判断

修改 src\utils\url.ts

js 复制代码
import { useMemo } from "react";
import { URLSearchParamsInit, useSearchParams } from "react-router-dom";
import { cleanObject } from "utils";
...
export const useUrlQueryParam = <K extends string>(keys: K[]) => {
  const [searchParams, setSearchParams] = useSearchParams();
  return [
    useMemo(
      () => keys.reduce((prev, key) => {
        // searchParams.get 可能会返回 null,需要预设值来兼容
        return { ...prev, [key]: searchParams.get(key) || "" };
        // 初始值会对类型造成影响,需要手动指定
      }, {} as { [key in K]: string }),
      // eslint-disable-next-line react-hooks/exhaustive-deps
      [searchParams]
    ),
    (params: Partial<{ [key in K]: unknown }>) => {
      const o = cleanObject({ ...Object.fromEntries(searchParams), ...params }) as URLSearchParamsInit
      return setSearchParams(o)
    },
  ] as const;
};
  • 遇到类似下面这样的类型不匹配问题,可以直接使用 as 来强制指定为提示的类型
    • 类型"{ [x: string]: unknown; }"的参数不能赋给类型"URLSearchParamsInit | ((prev: URLSearchParams) => URLSearchParamsInit) | undefined"的参数。

通过 Object.fromEntries 引出 Iterator 的概念:

Symbol.iterator 为每一个对象定义了默认的迭代器。该迭代器可以被 for...of 循环使用。

Symbol.iterator - JavaScript | MDN

在浏览器的 console 中做个小实验:

  • 定义一个数组并使用 for..of 遍历
js 复制代码
let arr = [1, 2, 3]
for(v of arr) { console.log(v) }
// 1
// 2
// 3
  • 通过 Symbol.iterator 属性查看 此数组的 遍历器
js 复制代码
arr[Symbol.iterator]
// ƒ values() { [native code] }
  • 将其执行结果拿出来
js 复制代码
let i = a[Symbol.iterator]()
i
// Array Iterator {}
//  [[Prototype]]: Array Iterator
//    next: ƒ next()
//    Symbol(Symbol.toStringTag): "Array Iterator"
//    [[Prototype]]: Object
  • 可以看到它有个 next() 方法,执行一下
js 复制代码
i.next()
// {value: 1, done: false}
i.next()
// {value: 2, done: false}
i.next()
// {value: 3, done: false}
i.next()
// {value: undefined, done: true}
  • 接下来实现一下自定义遍历器
js 复制代码
const obj = {
  data: ["hello", "world"],
  [Symbol.iterator]() {
    const self = this;
    let index = 0;
    return {
      next() {
        if (index < self.data.length) {
          return {
            value: self.data[index++] + "!",
            done: false
          };
        } else {
          return { value: undefined, done: true };
        }
      }
    };
  }
};

for (let o of obj) {
  console.log(o);
}

线上地址:https://codesandbox.io/s/upbeat-wood-bum3j

回归项目代码,searchParamsURLSearchParams 类型,通过以下代码可以看出使用 Object.fromEntries 可以将其(entries)转为 object

js 复制代码
new URLSearchParams({name: 'Jack'})[Symbol.iterator]
// ƒ entries() { [native code] }

代码逻辑明白了,接下来看下页面效果:

src\screens\ProjectList\index.tsx 中打印 param

src\screens\ProjectList\components\SearchPanel.tsx 中打印 users

运行代码可以发现,paramidstringusers 中是 number,没有很好兼容,暂时在src\screens\ProjectList\components\SearchPanel.tsx 中将 id 强制转换为 stringString(user.id)):

js 复制代码
...
export const SearchPanel = ({ users, param, setParam }: SearchPanelProps) => {
  return (
    <Form css={{ marginBottom: "2rem", ">*": "" }} layout="inline">
      ...
      <Form.Item>
        <Select {...}>
          <Select.Option value="">负责人</Select.Option>
          {users.map((user) => (
            <Select.Option key={user.id} value={String(user.id)}>...</Select.Option>
          ))}
        </Select>
      </Form.Item>
    </Form>
  );
};

查看页面效果,功能正常啦!


部分引用笔记还在草稿阶段,敬请期待。。。

相关推荐
万叶学编程3 小时前
Day02-JavaScript-Vue
前端·javascript·vue.js
前端李易安5 小时前
Web常见的攻击方式及防御方法
前端
PythonFun5 小时前
Python技巧:如何避免数据输入类型错误
前端·python
知否技术5 小时前
为什么nodejs成为后端开发者的新宠?
前端·后端·node.js
hakesashou5 小时前
python交互式命令时如何清除
java·前端·python
天涯学馆5 小时前
Next.js与NextAuth:身份验证实践
前端·javascript·next.js
HEX9CF5 小时前
【CTF Web】Pikachu xss之href输出 Writeup(GET请求+反射型XSS+javascript:伪协议绕过)
开发语言·前端·javascript·安全·网络安全·ecmascript·xss
ConardLi5 小时前
Chrome:新的滚动捕捉事件助你实现更丝滑的动画效果!
前端·javascript·浏览器
ConardLi6 小时前
安全赋值运算符,新的 JavaScript 提案让你告别 trycatch !
前端·javascript