React.memo 和 useMemo

现象

React 中,通常父组件的某个state发生改变,会引起父组件的重新渲染(和其他state的重新计算),从而会导致子组件的重新渲染(和其他非相关属性的重新计算)

  • 问题一: 如何避免因为某个state变化,导致组件的中其他属性(state)的重新计算?

**方案:**useMemo

  • 问题二: 如何避免因为父组件的重新渲染,导致子组件中非相关属性的重新计算?

**方案:**React.memo

结论

总结起来就一句话:

React.memo 用来限制组件重新渲染,而 useMemo用来限制组件中的部分变量重新计算

(前者主要针对组件的渲染,后者则侧重于组件内的计算)

示例

React.memo :【常用于子组件】

它是一个高阶组件(Higher-Order Component,HOC),用于包装函数组件

当父组件重新渲染时,往往会触发子组件的重新渲染。但很多时候子组件的 props 并没有改变,此时子组件的重新渲染就是不必要的,会造成性能浪费。

经过 React.memo 包装的组件,React 会对其 props 进行浅比较,如果新 props 和旧 props 相同,组件不会重新渲染,而是复用之前的渲染结果。(浅比较只会检查对象或数组的引用是否相同,而不会深入比较其内部的属性或元素)

javascript 复制代码
import React from 'react';

// 使用 React.memo 包裹组件
const MyComponent = React.memo(({ data }) => {
    console.log('组件重新渲染');
    return <div>{data}</div>;
});

const ParentComponent = () => {
    const [count, setCount] = React.useState(0);
    const someData = '固定数据';
    return (
        <div>
            {/* 如果子组件不用React.memo包裹,count变化后子组件也会重新渲染 */}
            <button onClick={() => setCount(count + 1)}>增加计数</button>

            {/* 只要 someData 不变,MyComponent 不会重新渲染 */}
            <MyComponent data={someData} />
        </div>
    );
};

export default ParentComponent;

useMemo

这是一个 React Hook,只能用于函数组件内部

它主要用于缓存计算结果,根据传入的依赖项数组来判断是否需要重新计算缓存的值,避免在每次组件渲染时都进行重复的高开销计算。

如果计算属性作为子组件的 props 传递,且子组件使用 React.memo 进行了优化,在父组件使用 useMemo 可以确保计算属性的引用在依赖项不变时保持稳定,从而避免子组件不必要的重新渲染。

javascript 复制代码
import React, { useState, useMemo, memo } from 'react';

const ChildComponent = memo(({ data }) => {
    console.log('ChildComponent rendered');
    return <div>{data}</div>;
});

const ParentComponent = () => {
    const [num, setNum] = useState(1);

    const calculatedData = useMemo(() => {
        return num * 2;
    }, [num]);

    return (
        <div>
            <input
                type="number"
                value={num}
                onChange={(e) => setNum(Number(e.target.value))}
            />
            <ChildComponent data={calculatedData} />
        </div>
    );
};

export default ParentComponent;

这里 calculatedData 通过 useMemo 缓存,当 num 不变时,calculatedData 的引用保持不变,ChildComponent 不会因为 props 的引用变化而重新渲染。

顺便提一下【useCallback】:

当父组件向子组件传递一个函数作为 props,并且子组件使用 React.memo 包裹时,useCallback 可以确保该函数的引用在依赖项不变时保持稳定,从而避免子组件因为函数引用的改变而进行不必要的重新渲染。

javascript 复制代码
import React, { useState, useCallback, memo } from 'react';

// 使用 React.memo 包裹子组件
const ChildComponent = memo(({ onClick }) => {
    console.log('ChildComponent 渲染');
    return <button onClick={onClick}>点击我</button>;
});

const ParentComponent = () => {
    const [count, setCount] = useState(0);

    // 使用 useCallback 缓存函数
    const handleClick = useCallback(() => {
        setCount(count + 1);
    }, [count]);

    return (
        <div>
            <p>计数: {count}</p>
            <ChildComponent onClick={handleClick} />
        </div>
    );
};

export default ParentComponent;
相关推荐
郭老二3 小时前
【前端】vue3:编译步骤
前端
不在逃避q4 小时前
Trae/Vs Code/Cursor命令行无法跑npm命令
前端·arcgis·npm
夏殇之殁4 小时前
包中创建自定义列表项。 . 使用自定义列表项进行数据绑定 . 将天气预报数据保存到本地内存表,通过LiveBindings进行显示。 ...
服务器·前端·javascript
The Chosen One9854 小时前
高进度算法模板速记(待完善)
java·前端·算法
陈随易4 小时前
MoonBit抓包模块pcap,查看电脑的每一次联网通信
前端·后端·程序员
新中地GIS开发老师5 小时前
WebGIS开发学生作品|低空航天管理与航线规划系统
前端·javascript·webgis·三维gis开发
用户059540174465 小时前
大模型对话记忆持久化踩坑实录:用 Playwright 自动化测了 300 次,终于揪出会话丢失的真凶
前端·css
丙氨酸長鏈6 小时前
Web前端入门第 问:JavaScript 一个简单的 IndexedDB 数据库入门示例
前端·javascript·数据库
kyriewen6 小时前
面试官让我手写虚拟列表——AI生成的版本,快速滚动几下就白屏了
前端·javascript·面试
IT_陈寒7 小时前
Vite热更新失效?你可能漏了这个配置
前端·人工智能·后端