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;

相关文章

显卡天梯图2024最新版,显卡是电脑进行图形处理的重要设备,...
初始化电脑时出现问题怎么办,可以使用win系统的安装介质,连...
todesk远程开机怎么设置,两台电脑要在同一局域网内,然后需...
油猴谷歌插件怎么安装,可以通过谷歌应用商店进行安装,需要...
虚拟内存这个名词想必很多人都听说过,我们在使用电脑的时候...