useMemo 和 useCallback —— React Hook

useMemo

一、作用

useMemomemo 作用相同,都是用来做性能优化的,不会影响业务逻辑。

memo函数,针对的是一个组件的渲染,是否重复执行。()
useMemo,定义了一段函数逻辑,是否重复执行。(() => {})

本质都是利用同样的算法,判断依赖是否发生改变,进而决定是否触发特定逻辑。

二、使用语法

import React, { useMemo } from 'react'

useMemo(() => {}, [] ) 

这里有几个注意点:

  1. useMemo的第一个参数是函数,第二个参数一般都为数组
  2. 如果不传第二个参数,与useEffect类似,意味着每一次都会执行第一个函数参数,那么使用useMemo的意义就没有了。
  3. 如果第二个参数传的是空数组[],与useEffect类似,只执行一次。
  4. useMemouseEffect有不一样的一点就是调用时机 —— useEffect执行的是副作用,所以一定是在渲染之后运行的;而useMemo是需要有返回值的,返回值会参与渲染,所以useMemo是是在渲染期间完成的。

三、具体demo代码

import React, { useState, useMemo } from 'react';

function App() {
    const [count, setCount] = useState(0);

    const double = useMemo(() => {
        return count * 2
    }, [count === 3])

  return (
      

count: {count}

double: {double}

) } export default App;

这里使用了count === 3这个表达式的结果(布尔值,true/false),作为是否重新渲染Double组件的判断依据。

所以随着count从0开始的每一次的加一,Double组件最终也只会重新渲染两次:

  • 当count值为3的时候,count === 3这个表达式的结果为true,发生改变了。
  • 当count值为4的时候,count === 3这个表达式的结果为false,发生改变了。

结果演示:


useMemo 和 useCallback —— React Hook_第1张图片
初始状态

useMemo 和 useCallback —— React Hook_第2张图片
点了两次按钮,double没变

useMemo 和 useCallback —— React Hook_第3张图片
当count为3时,double终于变了

useMemo 和 useCallback —— React Hook_第4张图片
count为4时,double也变为8

useMemo 和 useCallback —— React Hook_第5张图片
之后就再也没变化过了

三、useMemo中依赖的值,也可以是一个useMemo

但千万要注意,不要循环依赖!

import React, { useState, useMemo } from 'react';

function App() {
    const [count, setCount] = useState(0);

    const double = useMemo(() => {
        return count * 2
    }, [count === 3])

    const half = useMemo(() => {
        return count / 2
    }, [double])


  return (
      

count: {count} double: { double } half: { half }

) } export default App;
useMemo 和 useCallback —— React Hook_第6张图片
useMemo 和 useCallback —— React Hook_第7张图片
half只有在double发生变化的时候才变化

四、优化子组件重渲染的场景

1. 先展示还没优化前的场景

可以观察到,每一次App组件里的count加1,Counter子组件就会重新渲染一次(控制台输出)。

import React, { useState, useMemo } from 'react';

function Counter(props) {
    console.log('Counter');
    return (
        

Counter: {props.counter}

) } function App() { const [count, setCount] = useState(0); const double = useMemo(() => { return count * 2 }, [count === 3]) return (

count: {count}

) } export default App;
2. 使用memo来优化Counter子组件

可以观察到,经过这一步骤优化后,只有当App组件里的count值为34的时候,Counter子组件才会重新渲染(控制台输出)。

import React, { useState, useMemo, memo } from 'react';

const Counter = memo(function Counter(props) {
    console.log('Counter');
    return (
        

Counter: {props.counter}

) }) function App() { const [count, setCount] = useState(0); const double = useMemo(() => { return count * 2 }, [count === 3]) return (

count: {count}

) } export default App;
3.给Counter组件传递onClick属性

尽管Counter子组件里的counter值,只会在App组件的count值为3和4的时候才会更新。但是每一次count值变化,Counter组件都会重新渲染,这是意料之外的场景。说明每一次App的变化,都会到处onClick也被连带重新渲染了。

import React, { useState, useMemo, memo } from 'react';

const Counter = memo(function Counter(props) {
    console.log('Counter');
    return (
        

Counter: {props.counter}

) }) function App() { const [count, setCount] = useState(0); const double = useMemo(() => { return count * 2 }, [count === 3]) const onClick = () => { console.log('click') } return (

count: {count}

) } export default App;
4. 使用useMemo来让onClick不会每次都渲染

使用useMemo(() => { return onClick }, [])来包裹onClick函数,让它不会每一次都重新渲染,就只渲染一次。

可以发现优化成功了,只有当App组件里的count值为3和4的时候,Counter组件才有重新渲染。

import React, { useState, useMemo, memo } from 'react';

const Counter = memo(function Counter(props) {
    console.log('Counter');
    return (
        

Counter: {props.counter}

) }) function App() { const [count, setCount] = useState(0); const double = useMemo(() => { return count * 2 }, [count === 3]) const onClick = useMemo(() => { return () => { console.log('click') } }, []) return (

count: {count}

) } export default App;
5. 使用useCallback来省略顶层的useMemo函数

刚刚第4点的优化中,onClick的具体优化代码为:

const onClick = useMemo(() => {
        return () => {
            console.log('click')
        }
}, [])

可以观察到这里有两层函数。

useCallback

useCallback就是useMemo可以省略一层函数的写法。
useMemo(() => fn, []) 就等于 useCallback(fn, [])

可以观察到这里有两层函数:

const onClick = useMemo(() => {
        return () => {
            console.log('click')
        }
}, [])

使用useCallback来简写:

const onClick = useCallback(() => {
  console.log('click')
}, [])

完整代码:

import React, { useState, useMemo, memo, useCallback } from 'react';

const Counter = memo(function Counter(props) {
    console.log('Counter');
    return (
        

Counter: {props.counter}

) }) function App() { const [count, setCount] = useState(0); const double = useMemo(() => { return count * 2 }, [count === 3]) const onClick = useCallback(() => { console.log('click') }, []) return (

count: {count}

) } export default App;

你可能感兴趣的:(useMemo 和 useCallback —— React Hook)