详细了解 useCallBack useMemo useState

79 阅读2分钟

useCallBack(fn,deps)

const handleCount1 = useCallback(() => {
    setCount1(count1+1);
},[count1]);
  • return fn
  • useCallBack需要配合React.memo使用
  • useCallBack缓存的是函数地址,如果依赖的数据改变了,会返回一个新的内存地址,否则把旧函数内存地址返回;在子组件中需要使用memo检测props数据栈中内存地址是否有变化,如果栈地址改变,意味着useCallBack返回了新函数地址,那么子组件就会重新渲染。注意:useCallBack只是监听数据的内存地址是否发生变化,并不能防止组件的渲染。

parent.jsx

import React, {useCallback, useContext, useState} from "react";
import Child from "./child";



const Parent = () => {
    const [count,setCount] = useState(1)

    const handleShow = () => {
        console.log("传入子组件的函数")
    }

    return (
        <div>
            <button onClick={() => setCount(count+1)}>{count}</button>
            <Child show={handleShow}></Child>
        </div>
    )
}

export default Parent

child.jsx
```jsx
import React from "react";

const Child = React.memo(() => {

console.log("子组件重新渲染了")

    return (
    <div>子组件</div>
    )
})

export default Child

image.png 点击button时,子组件也会重新渲染。当父组件渲染的时候,会重新构建所有的函数,销毁旧函数,memo会因为props中的函数内存地址每次都变化来重新渲染子组件。

子组件怎样才不更新?

import React, {useCallback, useContext, useState} from "react";
import Child from "./child";



const Parent = () => {
    const [count,setCount] = useState(1)
    //使用  useCallback
    const handleShow = useCallback(() => {
        console.log("传入子组件的函数")
    },[])

    return (
        <div>
            <button onClick={() => setCount(count+1)}>{count}</button>
            <Child show={handleShow}></Child>
        </div>
    )
}

export default Parent

点击button,子组件不会重新渲染,控制台只在初始渲染时输出了一次;子组件没有重复渲染

useMemo(() => fn,deps)


useMemo(() => {
   setCount2(count2+1)
 },[count2]);
  • return value

  • useCallBack(fn,[deps]) 等价于 useMemo(() => fn,[deps])

  • 每一个在callback中出现的值都应该作为deps useCallBack useMemo 会对依赖的数据以及返回值进行缓存,只有依赖改变的时候才会重新执行,否则就使用缓存。

  • 使用场景: 当父组件传递给子组件方法或数据时,只要父组件一改变,其子组件也会重新渲染,而渲染是很消耗性能的,因此可以给传递给子组件的方法使用useCallBack,给传递给子组件的数据使用useMemo,但还是要适当的使用。

useState的疑惑

很多时候改变了状态数据的值,但却获取不到最新的值,总是感觉慢一拍。这是由于使用hooks,状态数据的改变是异步的,不能改变数据之后就立即获取到数据的值,因此,可以通过useEffect依赖状态数据,当数据改变时,获取到最新的值。


import React, {useState, useCallback, useMemo, useTransition, useEffect} from "react";


const TestHooks = () => {
    const [count1,setCount1] = useState(1)
    const [count2,setCount2] = useState(1)
    const [count3,setCount3] = useState(1)

    const handleCount1 = useCallback(() => {
        setCount1(count1+1)
        console.log(" handleCount1 count1",count1)
    },[count1]);

    const handleCount3 = () => {
        setCount3(count3+1)
        console.log("handleCount3 count3",count3)
    }
    
    useEffect(() => {
        console.log("count1,count2,count3",count1,count2,count3)
    },[count1,count2,count3])

    return (
        <div>
            <button onClick={handleCount1}>count1:{count1}</button>
            <button onClick={() => {setCount2(count2+1); console.log("setCount2 count2",count2)}}>count2:{count2}</button>
            <button onClick={handleCount3}>count3:{count3}</button>
        </div>
    )

}
export default TestHooks

上面的setCount2(count2+1)改变count2的值,但是后面的console.log并不会打印出count2最新的值,是上一次的值;使用useEffect依赖count2,可打印出count2最新的值。