• 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;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
  • 相关阅读:
    MATLAB读取图片时报错:“错误使用 fopen 找不到文件,确保文件存在且路径” 的原因及解决方法
    大数据之Hive
    spark学习总结
    人员位置管理,点亮矿山安全之路
    source /etc/profile卡住不动
    一篇文章带你使用(MMKV--基于 mmap 的高性能通用 key-value 组件)
    MyBatisPlus快速入门
    linux系统编程 (四) gdb调试与makefile
    新方向!文心一言X具身智能,用LLM大模型驱动智能小车
    龙芯 Loongson 架构 UOS 系统编译 Qt 5.15.2 源码
  • 原文地址:https://blog.csdn.net/weixin_42606338/article/details/126494561