[Practice] Seven, Hook, routing, and URL state management (Part 2) —— React17+React Hook+TS4 best practice, imitating Jira enterprise-level project (13)


Source of learning content: React + React Hook + TS Best Practice - MOOC


Compared with the original tutorial, I used the latest version at the beginning of my study (2023.03):

item Version
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

The specific configuration, operation and content will be different, and the "pit" will also be different. . .


1. Project launch: project initialization and configuration

2. React and Hook application: implement the project list

3. TS Application: JS God Assist - Strong Type

4. JWT, user authentication and asynchronous request


5. CSS is actually very simple - add styles with CSS-in-JS


6. User experience optimization - loading and error state handling



7. Hook, routing, and URL state management

1+2.

3~6

7. Complete the explanation of URL state management and iterator in JS

searchParamsGot it, and then use the exposed one setSearchParamsto replace ProjectListthe one insetParam

Modify src\screens\ProjectList\index.tsx:

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

However, setParamif you pass in a { name1: 'Jack' }parameter when using in this way, there is no error interception, which will definitely not work, so you need setParamto setSearchParamsuse keythe judgment of in the immediate

Modify src\utils\url.ts:

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;
};
  • If you encounter a type mismatch problem like the following, you can directly use asto force the type specified as the prompt
    • 类型“{ [x: string]: unknown; }”的参数不能赋给类型“URLSearchParamsInit | ((prev: URLSearchParams) => URLSearchParamsInit) | undefined”的参数。

Object.fromEntriesThe concept introduced by Iterator:

Symbol.iteratorA default iterator is defined for each object. This iterator can be for...ofrecycled.

Symbol.iterator - JavaScript | MDN

consoleDo a little experiment in your browser :

  • Define an array and for..ofiterate over it using
let arr = [1, 2, 3]
for(v of arr) {
    
     console.log(v) }
// 1
// 2
// 3
  • Symbol.iteratorA iterator to view this array via the property
arr[Symbol.iterator]
// ƒ values() { [native code] }
  • Take out its execution result
let i = a[Symbol.iterator]()
i
// Array Iterator {}
//  [[Prototype]]: Array Iterator
//    next: ƒ next()
//    Symbol(Symbol.toStringTag): "Array Iterator"
//    [[Prototype]]: Object
  • You can see that it has a next()method, execute it
i.next()
// {value: 1, done: false}
i.next()
// {value: 2, done: false}
i.next()
// {value: 3, done: false}
i.next()
// {value: undefined, done: true}
  • Next, implement a custom traverser
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);
}

Online address: https://codesandbox.io/s/upbeat-wood-bum3j

The return item code searchParamsis URLSearchParamsof the type, and it can be seen from the following code that Object.fromEntriesit can be entriesconverted ( ) intoobject

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

The code logic is clear, let's look at the page effect:

  • http://localhost:3000/projects?name=rider&personId=18 direct access, parameters are kept on the page
  • Modify the parameters on the page, and change the URL at the same time, but there is a small problem. When the person in charge is selected from the drop-down list, the page is displayed. Let’s solve it personIdnext.

src\screens\ProjectList\index.tsxprint param in

src\screens\ProjectList\components\SearchPanel.tsxprint users in

Running the code, we can find that paramin idis stringbut usersin is number, it is not very compatible, temporarily src\screens\ProjectList\components\SearchPanel.tsxconvert idto string( String(user.id)):

...
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>
  );
};

Check the page effect, the function is normal!


Some reference notes are still in draft stage, so stay tuned. . .

Guess you like

Origin blog.csdn.net/qq_32682301/article/details/131813894