1、函数组件的声明方式及差异

  • 普通函数声明

  • 箭头函数声明

  • 使用React.FC类型(TypeScript专用)

    interface Props {
    content: string
    } // 写法一
    const MyComponent: React.FC<Props> = (props) => {
    return <div>{props.content}</div>
    } // 写法二, FC 是 React.FC 的简写别名,二者完全等价。
    import { FC } from 'react'
    const MyComponent: FC<Props> = (props) => {
    return <div>{props.content}</div>
    }
  • 使用React.memo优化

    const MemoizedComponent = React.memo(function MyComponent(props) {
    return <div>{props.content}</div>;
    });

2、React.memo和userCallback

React.memo

  1. 介绍及使用时机

    React.memo 是什么:一个用于函数组件的性能优化工具,通过浅比较 props 避免无效渲染。

    何时使用

    • 组件渲染成本高
    • 父组件频繁更新但子组件 props 不变
    • 需要精细化控制渲染逻辑

    如何正确使用

    • 对简单 props 使用默认浅比较
    • 对复杂 props 结合 useMemo/useCallback
    • 必要时自定义比较函数
  2. 基本用法

    import React from 'react';
    
    const MyComponent = (props) => {
    return <div>{props.content}</div>;
    }; // 用 React.memo 包裹组件
    export default React.memo(MyComponent);
  3. 自定义比较逻辑(高级用法)

    如果默认的浅比较不满足需求,可以手动控制比较逻辑:

    // 第二个参数是自定义比较函数
    export default React.memo(MyComponent, (prevProps, nextProps) => {
    // 返回 true 表示 props "相同",阻止渲染
    // 返回 false 表示 props "不同",允许渲染
    return prevProps.id === nextProps.id;
    });
  4. 使用场景案例

    场景 1:父组件频繁更新,但子组件不需要
    
    // 父组件
    const Parent = () => {
    const [count, setCount] = useState(0); return (
    <div>
    <button onClick={() => setCount(count + 1)}>点击 {count}</button>
    {/* 即使 count 变化,Child 的 props 未变化 */}
    <Child title="静态内容" />
    </div>
    );
    }; // 子组件用 React.memo 包裹
    const Child = React.memo(({ title }) => {
    console.log('子组件渲染'); // 只有 title 变化时才会打印
    return <div>{title}</div>;
    }); 场景 2:复杂数据渲染
    // 大数据表格组件
    const DataTable = React.memo(({ data }) => {
    // 假设 data 有 10,000 行数据
    return (
    <table>
    {data.map(row => (
    <tr key={row.id}><td>{row.value}</td></tr>
    ))}
    </table>
    );
    });

useCallback

  1. 核心作用

    useCallback 是 React 的一个性能优化 Hook,用于 缓存函数引用

    它的核心价值是 避免父组件重新渲染时,因函数引用变化导致子组件无效渲染

  2. 解决什么问题?

    • 问题场景

      当父组件传递一个函数给子组件时,若父组件更新,每次会重新创建该函数。即使子组件用 React.memo 包裹,也会因函数引用不同而触发重新渲染。
    • 优化目标

      保持函数引用不变,除非依赖项变化,从而减少子组件无效渲染。

    问题场景:

    // 父组件
    const Parent = () => {
    const [count, setCount] = useState(0); // 每次 Parent 渲染都会创建新的 handleClick 函数
    const handleClick = () => {
    console.log('点击事件');
    }; return (
    <div>
    <button onClick={() => setCount(count + 1)}>触发渲染(当前:{count})</button>
    {/* 即使 Child 用 React.memo 包裹,仍会重新渲染 */}
    <Child onClick={handleClick} />
    </div>
    );
    }; // 子组件(用 React.memo 优化)
    const Child = React.memo(({ onClick }) => {
    console.log('子组件渲染'); // 父组件每次更新都会触发此日志
    return <button onClick={onClick}>子组件按钮</button>;
    }); // 问题:父组件每次更新(如 count 变化)时,handleClick 会被重新创建,导致传递给子组件的 onClick 引用不同。
    // 结果:即使子组件用 React.memo 包裹,也会因 props 中函数的引用变化而重新渲染。
  3. 语法与参数

    const memoizedFn = useCallback(
    () => { /* 函数逻辑 */ },
    [dep1, dep2] // 依赖项数组
    );
    // 参数 1:需要缓存的函数。
    // 参数 2:依赖项数组(类似 useEffect 的依赖)。
    // 返回值:一个记忆化的函数引用(依赖不变时引用不变)。 // 正确:依赖项包含 count,避免形成闭包并解决
    const handleClick = useCallback(() => {
    console.log(count);
    }, [count]);

区别

useCallback useMemo
缓存目标 缓存函数本身 缓存函数的计算结果(值/对象)
返回值 函数引用 计算结果
等效写法 useMemo(() => fn, deps) useMemo(() => value, deps)

2025/04/15

函数组件的声明方式及差异+React.memo和userCallback区别的更多相关文章

  1. vue组件常用声明方式

    一.前言 这是自己重新写的一个,感觉以前的太写了很多不必要的方式 实际当中基本不会用的 所以自己写了一个常用的组件什么方式 更加的通俗易懂 二.代码如下 <!DOCTYPE html> & ...

  2. React.memo

    介绍React.memo之前,先了解一下React.Component和React.PureComponent. React.Component React.Component是基于ES6 class ...

  3. React组件复用的方式

    React组件复用的方式 现前端的工程化越发重要,虽然使用Ctrl+C与Ctrl+V同样能够完成需求,但是一旦面临修改那就是一项庞大的任务,于是减少代码的拷贝,增加封装复用能力,实现可维护.可复用的代 ...

  4. react hooks 如何自定义组件(react函数组件的封装)

    前言 这里写一下如何封装可复用组件.首先技术栈 react hooks + props-type + jsx封装纯函数组件.类组件和typeScript在这不做讨论,大家别白跑一趟. 接下来会说一下封 ...

  5. React 函数组件

    React 函数组件 1.定义方式 React 函数组件是指使用函数方法定义的组件. 定义方式:与函数的定义方式相同,需要将内容 return 出来,需要注意的是最外层只有一个标签或者使用<&g ...

  6. JavaScript 函数的两种声明方式

    1.函数声明的方式 JavaScript声明函数有两种选择:函数声明法,表达式定义法. 函数声明法 function sum (num1 ,num2){ return num1+num2 } 表达式定 ...

  7. JS定义函数的两种方式:函数声明和函数表达式

    函数声明 关于函数声明的方式,它的一个重要的特性就是函数声明提升(function declaration hoisting),意思是在执行代码之前会先读取函数声明.这就意味着可以把函数声明放在调用它 ...

  8. javascript函数声明方式

    javascript中函数的声明有三种方式: 最常见的函数声明: fun();//可以调用,因为这种声明方式会被浏览器优先加载. function fun() { alert("声明式的函数 ...

  9. JS中var声明与function声明两种函数声明方式的区别

    JS中常见的两种函数声明(statement)方式有这两种: // 函数表达式(function expression) var h = function() { // h } // 函数声明(fun ...

  10. js中声明函数的三种方式

    己亥年  庚午月 癸巳日  宜入宅 忌婚嫁 函数声明方式 声明 : function first(){}: 调用:first() 函数表达式声明方式   声明: var second=function ...

随机推荐

  1. kali 2019-04版安装问题

    在这里主要解决的是kali的undercover mode 存在BUG,切换后出现无法还原.或还原失败的情况. 如果要解决的是中文乱码.kali桌面种类与安装和kali桌面切换的问题,直接看最底部的连 ...

  2. web95 比较麻烦的interval绕过

    审计 include("flag.php"); highlight_file(__FILE__); if(isset($_GET['num'])){ $num = $_GET['n ...

  3. Tesseract-OCR使用有感

    这玩意儿就只有一个Tesseract.dll 就算有其它的加上x64目录下的另外两个dll leptonica-1.80.0.dll  tesseract41.dll也不过几兆而已,但是 但是 但是 ...

  4. Atcoder ABC329E Stamp 题解 [ 绿 ] [ 线性 dp ]

    Stamp:难点主要在 dp 转移的细节与分讨上,但通过改变状态设计可以大大简化分讨细节的题. 观察 首先要有一个观察:只要某一个前缀能被覆盖出来,那么无论它后面多出来多少,后面的字符串都可以帮他重新 ...

  5. 每次下载idea都必装的十个插件!

    IDEA必备插件 Alibaba Java Coding Guidelines 功能: 阿里巴巴Java开发规范插件,用于代码规范检查. 特点: 基于阿里巴巴Java开发手册,提供实时代码规范检查,帮 ...

  6. [BZOJ3600] 没有人的算术 题解

    妙不可言!妙绝人寰! 单点修,区间查,包是线段树的.考虑如何比较两节点大小. 考虑二叉搜索树,我们只要再给每个节点附一个权值,就可以比较了! 注意力相当惊人的注意到,假如给每个点一个区间 \([l_x ...

  7. EasyExcel合并行处理并优化

    业务场景 由于业务需要导出如下图中订单数据和订单项信息,而一个订单对应多个订单项,所以会涉及到自定义合并行 1.简单处理项目使用的EasyExcel,经查找发现Excel种有个AbstractMerg ...

  8. mybatis - [07] 模糊查询

    题记部分 (1)mapper类 List<User> getUserLike(String value); (2)mapper.xml <!-- 写法1 --> <sel ...

  9. 低代码 + DeepSeek:赋能开发者,效率飞跃新高度

    活字格接入 DeepSeek 前段时间,小编陆续发布了关于葡萄城旗下产品 Wyn 和 SpreadJS 成功接入DeepSeek的技术文章,分享了两款产品与 DeepSeek 集成后的功能优势和应用场 ...

  10. PHP检测用户是否关闭浏览器的方法

    1.例子1 echo str_repeat(" ",3000); ignore_user_abort(true); mylog('online'); while (true) { ...