一个前端,爱跑步、爱吉他、爱做饭、爱生活、爱编程、爱南芳姑娘,爱我所爱。世间最温暖又无价的是阳光、空气与爱,愿它们能带你去更远的地方。

  • 文章
  • 心情
  • 照片墙
  • 留言板
  • 工具
  • 友链
  • biaoblog

    专注web开发技术分享

    react杂七杂八学习记录(2025-6-13归档)

    技术 13 2025-06-13 15:46

    1.useMemo

    在优化代码和提高组件计算性能时推荐使用useMemo

    作用:记住计算结果,避免重复计算

    当你有一个计算量比较大的值时,或者这个值的计算依赖某些 props/state,useMemo 可以在依赖没变的情况下跳过计算,直接复用上一次的结果

    示例说明

    const MyComponent = ({ items }) => {
     const expensiveCalculation = (data) => {
      console.log("Calculating...");
      return data.reduce((acc, item) => acc + item, 0);
     };
    
     const total = useMemo(() => expensiveCalculation(items), [items]);
    
     return <div>Total: {total}</div>;
    };
    

    如果 items 没变,即使组件重新渲染,expensiveCalculation 也不会重新执行。



    2.useRequest

    注意着不是react原生提供的hook,而是ahooks库封装的

    目的是用来简化和增强请求操作的体验

    1. 自动处理 loading、error、data 状态
    2. 支持手动触发/自动触发请求
    3. 支持取消请求、轮询、刷新、分页、并发等高级功能
    4. 支持缓存、依赖刷新等功能
    5. 更少的样板代码,更高的可维护性


    与传统方法对比的示例:

    useRequest

    import { useRequest } from 'ahooks';
    import { getUserInfo } from './services';
    
    export default () => {
     const { data, error, loading } = useRequest(getUserInfo);
    
     if (loading) return <div>加载中...</div>;
     if (error) return <div>出错了</div>;
    
     return <div>用户名:{data.name}</div>;
    };
    

    getUserInfo 通常是一个promise方法

    import axios from 'axios';
    
    export async function getUserInfo() {
      const response = await axios.get('/api/user/info');
      return response.data;
    }
    
    

    手动触发请求:

    const { run, loading } = useRequest(fetchData, { manual: true });
    
    <Button onClick={() => run(params)}>点击获取数据</Button>
    

    手动触发(manual: true):


    传统写法

    const [loading, setLoading] = useState(false);
    const [data, setData] = useState(null);
    
    useEffect(() => {
      setLoading(true);
      fetchData().then(res => {
        setData(res);
      }).finally(() => {
        setLoading(false);
      });
    }, []);
    



    3.React.memo/useMemo/useCallback 配合使用

    用于子组件的缓存

    默认情况下 当父组件重新渲染时,子组件也会重新渲染

    但是如果这个子组件的复杂度很大,且依赖的父组件数据没有变化,则不需要重新渲染

    就可以使用React.memo套一下,把子组件缓缓起来

    const Parent = () => {
      const [count, setCount] = useState(0);
    
      console.log('👨‍👦 父组件渲染');
    
      return (
        <div>
          <button onClick={() => setCount(count + 1)}>加一</button>
          <Child name="小明" />
        </div>
      );
    };
    
    const Child = React.memo(({ name }) => {
      console.log('👶 子组件渲染');
      return <div>Hello {name}</div>;
    });
    


    想要正确的使用react.memo 需要看传递的数据 或者方法

    如果是方法 就必须使用useCallback来缓存方法

    如果是数据类型的,且是引用类型的,就必须使用useMemo来缓存引用类型

    (useCallback 似乎只有在配合React.memo时才有效果

    不像useMemo 它似乎也可以单独的去缓存使用)

    import React, { useState, useCallback, useMemo } from 'react';
    
    const Child = React.memo(({ count, onClick, config }) => {
      console.log('👶 Child rendered');
      return (
        <div style={{ border: '1px solid #ccc', padding: 10 }}>
          <p>Count: {count}</p>
          <p>Theme: {config.theme}</p>
          <button onClick={onClick}>Click Me</button>
        </div>
      );
    });
    
    export default function App() {
      const [parentCount, setParentCount] = useState(0);
    
      // ✅ 原始值:直接传,不需要 useMemo
      const count = parentCount;
    
      // ✅ useCallback:缓存函数引用
      const handleClick = useCallback(() => {
        console.log('Button clicked!');
      }, []);
    
      // ✅ useMemo:缓存对象引用
      const config = useMemo(() => ({ theme: 'dark' }), []);
    
      return (
        <div>
          <h2>Parent Count: {parentCount}</h2>
          <button onClick={() => setParentCount(c => c + 1)}>+1 Parent Count</button>
    
          <Child count={count} onClick={handleClick} config={config} />
        </div>
      );
    }
    


    4.多层组件嵌套时,useeffect执行顺序

    多层嵌套里,useEffect 执行顺序依然是从最外层父组件开始,逐层往里依次执行。也就是说:

    假设组件关系:A -> B -> C -> D

    执行顺序是:

    A useEffect
    B useEffect
    C useEffect
    D useEffect
    

    卸载清理函数执行顺序是:

    子组件先清理 → 一层层向上到父组件,也就是:

    D 卸载清理函数
    C 卸载清理函数
    B 卸载清理函数
    A 卸载清理函数
    


    5.reselect.js

    主要是配合redux来通过缓存仓库数据,提高性能

    使用场景多个页面使用了同样的仓库中衍生出来的计算结果(派生数据)

    希望把这个结果给缓存下来,避免重复的计算

    A/B/C 三个页面都需要用到一个仓库的派生数据

    如果先到A页面,如果仓库的源数据没有变化,那么就不会重复计算,直接返回上一次的派生数据结果

    B/C页面就避免了重复的计算过程

    代码示例

    react 组件a 引用

      const noPoachingCompany = useSelector(getNoPoachingCompany);
    

    selector.js 声明

    import { createSelector } from 'reselect';
    
    const getCompany = (state) => state.model.companies;
    
    export const getNoPoachingCompany = createSelector(
      [getCompany],
      (companies) => {
        return companies.filter((c) => c.noPoaching);
      },
    );
    


    6.长列表数据匹配优化方案

    通过id匹配 仓库中存储的用户列表(举例10万个用户),获取名字 这种方式

    第一种优化方法:使用reselect来进行匹配(如果传递的id重复出现,不会重复匹配计算,直接命中缓存,直接返回),但是有局限性,只能命中匹配上一次输入的id,无法记录多种数据

    第二种优化方法:自己写一个匹配方法,没成功匹配后,将结果存为一份mapping格式的数据,如果匹配到多个或者单个,直接返回,不需要重复循环匹配

    第三种优化方法:直接以mapping格式将用户表存入仓库,后续取值直接取值使用,不用循环匹配


    最佳的优化方案是第三种,因为这种方式是O(1)(输入多少都一样快,常数级时间)


    拓展

    O(1)是直接访问 不涉及遍历

    O(n)是遍历所有元素一变

    O(n²)是每个元素都和每个元素比较


    O(1):常数时间复杂度。
    直接访问数据,不管数据多少,操作次数基本固定。
    例子:数组通过索引访问 arr[5]
    O(n):线性时间复杂度。
    遍历所有元素,操作次数和数据量成正比。
    例子:遍历数组求和。
    O(n²):平方时间复杂度。
    对每个元素,都要和其他所有元素进行比较,操作次数是数据量的平方。
    例子:冒泡排序,两层嵌套循环比较数组中的每对元素。

    上一篇:没有了

    下一篇:npm electron拉取超时解决方案

    文章评论

    评论列表(0