react一些好用的库或方法

100
guojiabing
大佬推荐了一些比较优秀的库,这里做一些笔记,防止忘记!

ahooks

a就是alibaba 的第一个字母,也就是阿里加的产品!
它内置了一堆好用且实用的hooks!

useRequest

封装的http请求hook

  // 同步xxx,其中返回值都是响应式的状态
  const { data, loading, run } = useRequest(xxxPromise/apiUrl,{
      ready: Boolean(xxx), // 当有值后才会请求
      refreshDeps: [xxx], // 依赖项目变动则会更新请求
    }
  );
  • 设置返回值:通过返回的 mutate,可以手动更新data的值,如 mutate(xxx)
  • 手动触发:通过配置项manual = true,ready=true,再手动调返回的run方法

useControllableValue

可控状态,能给你一个“双向数据流”的感觉,即属性可以在子组件修改生效!
这里有一篇专门的文章

ts-pattern

在tsx中,如果条件渲染过于复杂,则需要大量的三元运算符参与,看起来及其不优雅!
ts-pattern 正是来解决这个问题的!

600

import { match, P } from 'ts-pattern';

type Data =
  | { type: 'text'; content: string }
  | { type: 'img'; src: string };

type Result =
  | { type: 'ok'; data: Data }
  | { type: 'error'; error: Error };

const result: Result = ...;

const html = match(result)
  .with({ type: 'error' }, () => <p>Oups! An error occured</p>)
  .with({ type: 'ok', data: { type: 'text' } }, (res) => <p>{res.data.content}</p>)
  .with({ type: 'ok', data: { type: 'img', src: P.select() } }, (src) => <img src={src} />)
  .otherwise(() => null)

immerjs

immerjs 不可变数据辅助库!

抛出问题

我们先来看一段代码,如下,当你点击完更新之后,再点击重制也回不去了!
这就是因为原始数据 personInit 应为 不可变数据,而你在调用update的时候给它改变了

import { useState } from 'react';

const personInit = {
  id: 20250101,
  name: '张三',
  age: 20,
};

const DemoThree = () => {
  const [person, setPerson] = useState(personInit);

  const update = () => {
    person.name = '李四';
    setPerson({...person});
  };

  const reset = () => {
    setPerson({...personInit});
  };
  
  return (
    <div className="wrapper">
      <div className="info">{JSON.stringify(person)}</div>
      <div className='flex gap-1'>
        <button onClick={update} className='bg-blue-400 text-white p-1 rounded'>更新</button>
        <button onClick={reset} className='bg-blue-400 text-white p-1 rounded'>重制</button>
      </div>
    </div>
  );
};

export default DemoThree;

自己解决

其实解决办法也简单,我们做个深拷贝即可,其它都不变的情况下,修改如下

 import _ from 'lodash';

// 封装 change 函数
const change = (state, updater) => {
  // 创建状态的深拷贝
  const nextState = _.cloneDeep(state);
  // 应用更新函数
  updater(nextState);
  return nextState;
};


const DemoThree = () => {
  const [person, setPerson] = useState(personInit);

  const update = () => {
    const newPerson = change(person, (draft) => {
      draft.name = '李四';
    });
    setPerson(newPerson);
  };

  const reset = () => {
    setPerson({ ...personInit });
  };

 // ...其它保持不变
}

使用三方库

如果我们不想自定义change函数,那么 immer 库就提供了这么一个函数!

  import {produce} from "immer"

  const update = () => {
    const newPerson = produce(person, (draft) => {
      draft.name = '李四';
    });
    setPerson(newPerson);
  };

当然这样来看,和我们自定change解决方案使用起来没什么太大区别,
进阶用法,结合react,immer提供了一个更好的钩子!

  import { useImmer } from "use-immer";

  const [person, setPerson] = useImmer(personInit);

  const update = () => {
    setPerson((draft) => {
      draft.name = '李四';
    });
  };

  const reset = () => {
    setPerson({ ...personInit });
  };

除此之外,使用immer的好处在于它 仅仅当内容发生变化时才会设置为新对象,否则依然是原对象(的引用),进而不会导致无用的reRender

posted @ 2025-09-04 11:11  丁少华  阅读(15)  评论(0)    收藏  举报