useCallback,useMemo与react,memo的区别与联系

写在前面:文章适合初级react-hook学习者使用,完整todoList例子及输出

React.memo: 使用场景,父组件中有多个部分组成,其中某些变量的变化并不会直接呈现在子组件中,但子组件中会在set***时同步更新,此部分更新可优化,此时将子组件React.memo处理即可

useCallback: 使用场景,在父组件中传递函数到子组件,如果在父组件中此函数不用useCallback处理,则父组件中无关set更新也会引起子组件的更新,而useCallback之后,只有依赖项set发生变化,子组件才会产生对应的更新

useMemo: 使用场景,在组件中需要对某些属性进行计算,获取计算后的结果,在一些无关的属性set***更新时会 同时刷新 该计算方法,使用useMemo后,该处的值,只有依赖项发生变化才会产生更新,类似于computed

import { Button, message } from 'antd';
import React, { useRef, useState, useCallback, useEffect, useMemo } from 'react'

function TodoList() {
    const ipt = useRef(null);
    const [todoItems, setTodoItem] = useState([]);
    const handleAdd = useCallback(() => {
        if (!ipt.current.value) {
            message.warning('todo item can not be empty.')
            return
        }
        const isExist = todoItems.find((item) => item.name === ipt.current.value)
        if (isExist) {
            message.warning('this todo item has exist.')
            return
        }
        const item = {
            id: new Date().getTime(),
            name: ipt.current.value
        };
        ipt.current.value = ""
        setTodoItem([...todoItems, item]);
    }, [todoItems]);

    const handleClear = useCallback(() => {
        setTodoItem([]);
    }, [todoItems]);

    const delItem = useCallback((delItem) => {
        const items = todoItems.filter((item) => item.id !== delItem.id)
        setTodoItem(items);
    }, [todoItems])

    const edit = useCallback((id, newItem) => {
        const items = [];
        todoItems.map((item) => {
            if (item.id === id) {
                items.push({ id: newItem.split('-')[0], name: newItem.split('-')[1] })
            } else {
                items.push(item)
            }
        })
        setTodoItem(items)
    }, [todoItems])

    const [text, setText] = useState('')
    const handleInput = (e) => {
        setText(e.target.value)
        const item = {
            id: new Date().getTime(),
            name: e.target.value
        };
        // setTodoItem([...todoItems, item]);
    }
    console.log('render-TodoList')

    return (
        <div>
            <input value={text} onChange={handleInput} />
            <input ref={ipt} />
            <Button onClick={handleAdd}>add todo&nbsp;</Button>
            <Button onClick={handleClear}>clear All</Button>
            <div>
                <Example />
            </div>
            {todoItems && todoItems.length > 0 ? todoItems.map((item) => {
                return (
                    <TodoItem data={item} key={item.id} delItem={delItem} edit={edit} />)
            }) : ''}
        </div>)
}


const Example = React.memo(() => {
    const [count, setCount] = useState(1);
    const [count1, setCount1] = useState(1);
    const [val, setValue] = useState('');
    console.log('123-Example');
    const getNum = useMemo(() => {
        console.log('234-Example-getNum');
        return Array.from({ length: count * 10 + count1 * 2 }, (v, i) => i).reduce((a, b) => a + b)
    }, [count, count1])

    const getNum1 = useCallback(() => {
        console.log('234-Example-getNum');
        return Array.from({ length: count * 10 + count1 * 2 }, (v, i) => i).reduce((a, b) => a + b)
    }, [count, count1])

    // useMemo:计算属性,返回的是值 只有依赖项发生修改,useMemo才会更新,可以有多个依赖项

    // useCallback: 缓存函数, 在父组件中传递函数到子组件,解决父组件中无关set更新引起的子组件更新,因为每次set更新时
    //              非callback函数都会重新生成,由此产生更新触发子组件的更新,而callback函数则为缓存函数,自有依赖项发生
    //              变化,子组件才会触发更新动作.

    return <div>
        <h4>总和:{getNum}</h4>
        <div>
            <Child getNum={getNum1} />
            <button onClick={() => setCount(count + 1)}>+1</button>
            <button onClick={() => setCount1(count1 + 1)}>+2</button>
            <input value={val} onChange={event => setValue(event.target.value)} />
        </div>
    </div>;
})

const Child = React.memo(({ getNum }) => {
    console.log('234-Example-getNum-Child');
    return <h4>总和:{getNum()}</h4>
})

// React.memo: 解决在同一个父组件中,屏蔽与子组件无关的set更新而引起的子组件刷新
const TodoItem = React.memo((props) => {
    console.log('render-todoItem')
    const item = props.data;
    const itemRef = useRef('');
    const [showInput, setShowInput] = useState(true);
    const handleEditable = useCallback(() => {
        if (!showInput) {
            props.edit(item.id, itemRef.current.value)
        }
        setShowInput(!showInput)
    }, [showInput])

    useEffect(() => {
        if (!showInput) {
            itemRef.current.value = item.id + '-' + item.name
        }
    }, [showInput])

    return (
        <div>
            {showInput ?
                <span>{item.id}-{item.name}</span>
                :
                <input ref={itemRef} />
            }
            <Button onClick={handleEditable}>{showInput ? 'edit' : 'save'}</Button>
            <Button onClick={() => props.delItem(item)}>delete</Button>
        </div>
    )
}
)
export default TodoList;

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习编程?其实不难,不过在学习编程之前你得先了解你的目的是什么?这个很重要,因为目的决定你的发展方向、决定你的发展速度。
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面设计类、前端与移动、开发与测试、营销推广类、数据运营类、运营维护类、游戏相关类等,根据不同的分类下面有细分了不同的岗位。
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生学习Java开发,但要结合自身的情况,先了解自己适不适合去学习Java,不要盲目的选择不适合自己的Java培训班进行学习。只要肯下功夫钻研,多看、多想、多练
Can’t connect to local MySQL server through socket \'/var/lib/mysql/mysql.sock问题 1.进入mysql路径
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 sqlplus / as sysdba 2.普通用户登录
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服务器有时候会断掉,所以写个shell脚本每五分钟去判断是否连接,于是就有下面的shell脚本。
BETWEEN 操作符选取介于两个值之间的数据范围内的值。这些值可以是数值、文本或者日期。
假如你已经使用过苹果开发者中心上架app,你肯定知道在苹果开发者中心的web界面,无法直接提交ipa文件,而是需要使用第三方工具,将ipa文件上传到构建版本,开...
下面的 SQL 语句指定了两个别名,一个是 name 列的别名,一个是 country 列的别名。**提示:**如果列名称包含空格,要求使用双引号或方括号:
在使用H5混合开发的app打包后,需要将ipa文件上传到appstore进行发布,就需要去苹果开发者中心进行发布。​
+----+--------------+---------------------------+-------+---------+
数组的声明并不是声明一个个单独的变量,比如 number0、number1、...、number99,而是声明一个数组变量,比如 numbers,然后使用 nu...
第一步:到appuploader官网下载辅助工具和iCloud驱动,使用前面创建的AppID登录。
如需删除表中的列,请使用下面的语法(请注意,某些数据库系统不允许这种在数据库表中删除列的方式):
前不久在制作win11pe,制作了一版,1.26GB,太大了,不满意,想再裁剪下,发现这次dism mount正常,commit或discard巨慢,以前都很快...
赛门铁克各个版本概览:https://knowledge.broadcom.com/external/article?legacyId=tech163829
实测Python 3.6.6用pip 21.3.1,再高就报错了,Python 3.10.7用pip 22.3.1是可以的
Broadcom Corporation (博通公司,股票代号AVGO)是全球领先的有线和无线通信半导体公司。其产品实现向家庭、 办公室和移动环境以及在这些环境...
发现个问题,server2016上安装了c4d这些版本,低版本的正常显示窗格,但红色圈出的高版本c4d打开后不显示窗格,
TAT:https://cloud.tencent.com/document/product/1340