小工具知识网

当前位置: 首页 > 行业知识 > 【实战】用 Custom Hook + TS泛型实现 useArray

行业知识

【实战】用 Custom Hook + TS泛型实现 useArray

2026-11-13 22:45:34 来源:互联网转载

文章目录

  • 一、题目
  • 二、答案(非标准)
  • 三、关键知识点
    • 1.Custom Hook
      • 关键点
      • 案例
        • useMount
        • useDebounce
        • 2.TS 泛型
          • 关键点

            一、题目

            完善自定义 Hook —— useArray ,使其能够完成 tryUseArray 组件中测试的功能:

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

                相关文件代码:

                • src\utils\index.ts
                  import { useEffect, useState } from "react";export const useMount = (cbk: () => void) => useEffect(() => cbk(), []);export const useArray = () => {};
                  • src\tryUseArray.tsx
                    import { useArray, useMount } from "utils";const TryUseArray = () => {  const persons: { name: string; age: number }[] = [    { name: "jack", age: 25 },    { name: "ma", age: 22 },  ];  const { value, clear, removeIndex, add } = useArray(persons);  useMount(() => {    // 期待这里报错:Property 'notExist' does not exist on type '{ name: string; age: number; }[]'.    // console.log(value.notExist);    // 期待这里报错:Property 'age' is missing in type '{ name: string; }' but required in type '{ name: string; age: number; }'.    // add({ name: "david" });    // 期待这里报错:Argument of type 'string' is not assignable to parameter of type 'number'.    // removeIndex("123");  });  return (          {/*期待: 点击以后增加 john */}      () = add({ name: "john", age: 22 })}>add john      {/*期待: 点击以后删除第一项*/}      () = removeIndex(0)}>remove 0      {/*期待:点击以后清空列表*/}      { marginBottom: "50px" }} onClick={() = clear()}>        clear            {value.map((person, index) => (        index} style={{ marginBottom: "30px" }}          { color: "red" }}{index}          {person.name}          {person.age}              ))}      );};export default TryUseArray;
                    • src\App.tsx
                      import "./App.css";import TryUseArray from "tryUseArray";function App() {  return (                );}export default App;

                      答 答 答

                      案 案 案

                      在 在 在

                      后 后 后

                      面 面 面

                      , , ,

                      没 没 没

                      有 有 有

                      完 完 完

                      成 成 成

                      不 不 不

                      要 要 要

                      偷 偷 偷

                      看 看 看

                      哦 哦 哦

                      ! ! !

                      二、答案(非标准)

                      import { useEffect, useState } from "react";// 我的练习作业// export const useArray = (array: T[]) => {//   const [value, setValue] = useState(array)//   const clear = () => setValue([])//   const removeIndex = (index: number) => setValue([...value].filter((item, _index) => _index !== index))//   const add = (item: item) => setValue([...value, item]))//   return {//     value, clear, removeIndex, add//   }// }export const useArray = (array: T[]) => {  const [value, setValue] = useState(array);  return {    value,    add: (item: T) => setValue([...value, item]),    removeIndex: (index: number) => {      const temp = [...value];      temp.splice(index, 1);      setValue(temp);    },    clear: () => setValue([]),  };};

                      三、关键知识点

                      1.Custom Hook

                      官方文档:自定义 Hook – React

                      关键点

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

                          案例

                          useMount
                          • 封装
                            export const useMount = (cbk: () => void) => useEffect(() => cbk(), []);
                            • 调用
                              import { useMount } from "utils";const [list, setList] = useState([]);useMount(() => {  fetch(`${apiUrl}/list`).then(async (res) => {    if (res.ok) {      setList(await res.json());    }  });});
                              useDebounce
                              • 封装
                                /** * @param { 值 } val * @param { 延时:默认 1000 } delay * @returns 在某段时间内多次变动后最终拿到的值(delay 延迟的是存储在队列中的上一次变化) */export const useDebounce = (val: V, delay: number = 1000) => {  const [tempVal, setTempVal] = useState(val);  useEffect(() => {    // 每次在 val 变化后,设置一个定时器    const timeout = setTimeout(() => setTempVal(val), delay);    // 每次在上一个 useEffect 处理完以后再运行(useEffect 的天然功能即是在运行结束的 return 函数中清除上一个(同一) useEffect)    return () => clearTimeout(timeout);  }, [val, delay]);  return tempVal;};
                                • 调用
                                  import { useDebounce } from "utils";// 对 param 进行防抖处理const lastParam = useDebounce(param);const [list, setList] = useState([]);useEffect(() => {  fetch(    // name=${param.name}&personId=${param.personId}    `${apiUrl}/projects?${qs.stringify(lastParam)}`  ).then(async (res) => {    if (res.ok) {      setList(await res.json());    }  });}, [lastParam]);

                                  注意区别于 节流

                                  拓展学习:

                                  • 【笔记】Custom Hook

                                    2.TS 泛型

                                    官方文档:

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

                                      关键点

                                      • 不预先指定其具体的类型,而在使用的时候再进行定义
                                      • 函数是对“值”的编程,泛型是对“类型”的编程
                                      • 泛型是类型的变量

                                        拓展学习:

                                        • 【笔记】TS 泛型

上一篇:解决验证码不置顶难题,手机显示问题一键解决!

下一篇:买个美国服务器怎么建立IP?