[web教学] 【实战】用 Custom Hook + TS泛型实现 useArray

[复制链接]
查看636 | 回复0 | 2023-8-23 11:55:10 | 显示全部楼层 |阅读模式 来自 中国北京

一、标题

完满自定义 Hook —— useArray ,使其可以大概完成 tryUseArray 组件中测试的功能:


  • 入参:数组
  • 返回值:

    • value:最新状态的数组;
    • add:添加元素;
    • removeIndex:移除数组特定位置的元素;
    • clear:清空数组;

相干文件代码:


  • src\utils\index.ts
  1. import { useEffect, useState } from "react";
  2. export const useMount = (cbk: () => void) => useEffect(() => cbk(), []);
  3. export const useArray = () => {};
复制代码


  • src\tryUseArray.tsx
  1. import { useArray, useMount } from "utils";
  2. const TryUseArray = () => {
  3.   const persons: { name: string; age: number }[] = [
  4.     { name: "jack", age: 25 },
  5.     { name: "ma", age: 22 },
  6.   ];
  7.   const { value, clear, removeIndex, add } = useArray(persons);
  8.   useMount(() => {
  9.     // 期待这里报错:Property 'notExist' does not exist on type '{ name: string; age: number; }[]'.
  10.     // console.log(value.notExist);
  11.     // 期待这里报错:Property 'age' is missing in type '{ name: string; }' but required in type '{ name: string; age: number; }'.
  12.     // add({ name: "david" });
  13.     // 期待这里报错:Argument of type 'string' is not assignable to parameter of type 'number'.
  14.     // removeIndex("123");
  15.   });
  16.   return (
  17.     <div>
  18.       {/*期待: 点击以后增加 john */}
  19.       <button onClick={() => add({ name: "john", age: 22 })}>add john</button>
  20.       {/*期待: 点击以后删除第一项*/}
  21.       <button onClick={() => removeIndex(0)}>remove 0</button>
  22.       {/*期待:点击以后清空列表*/}
  23.       <button style={{ marginBottom: "50px" }} onClick={() => clear()}>
  24.         clear
  25.       </button>
  26.       {value.map((person, index) => (
  27.         <div key={index} style={{ marginBottom: "30px" }}>
  28.           <span style={{ color: "red" }}>{index}</span>
  29.           <span>{person.name}</span>
  30.           <span>{person.age}</span>
  31.         </div>
  32.       ))}
  33.     </div>
  34.   );
  35. };
  36. export default TryUseArray;
复制代码


  • src\App.tsx
  1. import "./App.css";
  2. import TryUseArray from "tryUseArray";
  3. function App() {
  4.   return (
  5.     <div className="App">
  6.       <TryUseArray />
  7.     </div>
  8.   );
  9. }
  10. export default App;
复制代码
                                        答                                  答                     答
                                         案                                  案                     案
                                         在                                  在                     在
                                         后                                  后                     后
                                         面                                  面                     面
                                         ,                                  ,                     ,
                                         没                                  没                     没
                                         有                                  有                     有
                                         完                                  完                     完
                                         成                                  成                     成
                                         不                                  不                     不
                                         要                                  要                     要
                                         偷                                  偷                     偷
                                         看                                  看                     看
                                         哦                                  哦                     哦
                                         !                                  !                     !
二、答案(非标准)

  1. import { useEffect, useState } from "react";
  2. // 我的练习作业
  3. // export const useArray = <T>(array: T[]) => {
  4. //   const [value, setValue] = useState(array)
  5. //   const clear = () => setValue([])
  6. //   const removeIndex = (index: number) => setValue([...value].filter((item, _index) => _index !== index))
  7. //   const add = (item: item) => setValue([...value, item]))
  8. //   return {
  9. //     value, clear, removeIndex, add
  10. //   }
  11. // }
  12. export const useArray = <T>(array: T[]) => {
  13.   const [value, setValue] = useState(array);
  14.   return {
  15.     value,
  16.     add: (item: T) => setValue([...value, item]),
  17.     removeIndex: (index: number) => {
  18.       const temp = [...value];
  19.       temp.splice(index, 1);
  20.       setValue(temp);
  21.     },
  22.     clear: () => setValue([]),
  23.   };
  24. };
复制代码
三、关键知识点

1.Custom Hook

   官方文档:自定义 Hook – React
  关键点



  • 定义 Custom Hook 是一个函数,名字必须以 use 开头
  • hook 只能在 React 函数组件 或其他 Hook 函数中调用(平凡 js/ts 函数中不可用)
  • 类似的 Hook 不共享 state (重用状态逻辑的机制,所有 state 和副作用都是完全隔离的)
  • 不要在循环,条件或嵌套函数中调用 Hook(发起在 Hook 内部使用循环,条件或嵌套函数)
  • React 16.8+ 中使用
   

  • Hook 规则 – React
  案例

useMount



  • 封装
  1. export const useMount = (cbk: () => void) => useEffect(() => cbk(), []);
复制代码


  • 调用
  1. import { useMount } from "utils";
  2. const [list, setList] = useState([]);
  3. useMount(() => {
  4.   fetch(`${apiUrl}/list`).then(async (res) => {
  5.     if (res.ok) {
  6.       setList(await res.json());
  7.     }
  8.   });
  9. });
复制代码
useDebounce



  • 封装
  1. /**
  2. * @param { 值 } val
  3. * @param { 延时:默认 1000 } delay
  4. * @returns 在某段时间内多次变动后最终拿到的值(delay 延迟的是存储在队列中的上一次变化)
  5. */
  6. export const useDebounce = <V>(val: V, delay: number = 1000) => {
  7.   const [tempVal, setTempVal] = useState(val);
  8.   useEffect(() => {
  9.     // 每次在 val 变化后,设置一个定时器
  10.     const timeout = setTimeout(() => setTempVal(val), delay);
  11.     // 每次在上一个 useEffect 处理完以后再运行(useEffect 的天然功能即是在运行结束的 return 函数中清除上一个(同一) useEffect)
  12.     return () => clearTimeout(timeout);
  13.   }, [val, delay]);
  14.   return tempVal;
  15. };
复制代码


  • 调用
  1. import { useDebounce } from "utils";
  2. // 对 param 进行防抖处理
  3. const lastParam = useDebounce(param);
  4. const [list, setList] = useState([]);
  5. useEffect(() => {
  6.   fetch(
  7.     // name=${param.name}&personId=${param.personId}
  8.     `${apiUrl}/projects?${qs.stringify(lastParam)}`
  9.   ).then(async (res) => {
  10.     if (res.ok) {
  11.       setList(await res.json());
  12.     }
  13.   });
  14. }, [lastParam]);
复制代码
  留意区别于 节省
    拓展学习:
  

  • 【条记】Custom Hook
  2.TS 泛型

   官方文档:
  

  • TypeScript: Documentation - Generics
  • 泛型(generic) - TypeScript 中文手册
  关键点



  • 不预先指定其具体的范例,而在使用的时间再进行定义
  • 函数是对“值”的编程,泛型是对“范例”的编程
  • 泛型是范例的变量
   拓展学习:
  

  • 【条记】TS 泛型

来源:https://blog.csdn.net/qq_32682301/article/details/129382797
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则