useCallback、useMemo、memo

memo

import React, {useState} from 'react';
import ReactDOM from 'react-dom';

const ChildComponent = () =>{
  return (
    <>
      {console.log('子组件渲染')}
      <span>子组件</span>
    </>    
  )
}

const ParentComponent = () => {
  const [count, setCount] = useState(0);

  return (
    <>
      <h1>{count}</h1>
      <button onClick={e => setCount(c => c + 1)}>+1</button>
      <ChildComponent />
    </>
  )
}


ReactDOM.render(<ParentComponent />,  document.getElementById('root'));

定义了一个子组件,定义了一个父组件,我们希望在父组件count值变化的时候子组件不必重新渲染,但是发现在点击按钮的时候console.log会被执行:
在这里插入图片描述为了避免这种情况,可以在子组件外部包一个memo,memo会对props进行浅层比较。

const ChildComponent = memo(() =>{
  return (
    <>
      {console.log('子组件渲染')}
      <span>子组件</span>
    </>    
  )
})

useCallback

现在向子组件传递一个函数

import React, {useState, memo} from 'react';
import ReactDOM from 'react-dom';

const ChildComponent = memo(() =>{
  return (
    <>
      {console.log('子组件渲染')}
      <span>子组件</span>
    </>    
  )
})

const ParentComponent = () => {
  const [count, setCount] = useState(0);
  const fn = () => {
    console.log(1);
  }

  return (
    <>
      <h1>{count}</h1>
      <button onClick={e => setCount(c => c + 1)}>+1</button>
      <ChildComponent fn={fn}/>
    </>
  )
}


ReactDOM.render(<ParentComponent />,  document.getElementById('root'));

这时候我们发现虽然用memo包裹了子组件,但是点击+1以后仍然会重新渲染子组件,这是因为在点击+1时,父组件会重新执行,这样每次fn都会发生变化,传递给子组件的函数也就发生了变化。因此子组件会重新执行,但是我们不希望子组件重新执行,那么传递给fn的函数也不应该发生变化。

import React, {useState, memo, useCallback} from 'react';
import ReactDOM from 'react-dom';

const ChildComponent = memo(() =>{
  return (
    <>
      {console.log('子组件渲染')}
      <span>子组件</span>
    </>    
  )
})

const ParentComponent = () => {
  const [count, setCount] = useState(0);
  const fn = useCallback(() => {
    console.log(1);
  }, [])

  return (
    <>
      <h1>{count}</h1>
      <button onClick={e => setCount(c => c + 1)}>+1</button>
      <ChildComponent fn={fn}/>
    </>
  )
}


ReactDOM.render(<ParentComponent />,  document.getElementById('root'));

useCallback后面是依赖项,如果依赖项发生了改变函数才会重新变化。

useMemo

现在修改一下父组件

import React, {useState, memo, useCallback} from 'react';
import ReactDOM from 'react-dom';

const ChildComponent = memo(() =>{
  return (
    <>
      {console.log('子组件渲染')}
      <span>子组件</span>
    </>    
  )
})

const ParentComponent = () => {
  const [count, setCount] = useState(0);
  const fn = useCallback(() => {
    console.log(1);
  }, [])
  const fn2 = () => {
    console.log('fn2执行');
    let temp = 0;
    for (let i = 0; i < 100; i++) {
      temp += i;
    }
    return temp;
  }
  fn2()

  return (
    <>
      <h1>{count}</h1>
      <button onClick={e => setCount(c => c + 1)}>+1</button>
      <ChildComponent fn={fn}/>
    </>
  )
}


ReactDOM.render(<ParentComponent />,  document.getElementById('root'));

每次更新count的时候父组件都会被重新执行,那么每次fn2都要被重新计算一次,这时候就可以用useMemo来进行优化,返回一个memorized的值

把“创建”函数和依赖项数组作为参数传入 useMemo,它仅会在某个依赖项改变时才重新计算 memoized 值。这种优化有助于避免在每次渲染时都进行高开销的计算。

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

const ChildComponent = memo(() =>{
  return (
    <>
      {console.log('子组件渲染')}
      <span>子组件</span>
    </>    
  )
})

const ParentComponent = () => {
  const [count, setCount] = useState(0);
  const fn = useCallback(() => {
    console.log(1);
  }, [])
  const fn2 = () => {
    console.log('fn2执行');
    let temp = 0;
    for (let i = 0; i < 100; i++) {
      temp += i;
    }
    return temp;
  }
  const memorizedValue = useMemo(() => fn2(), [])

  return (
    <>
      <h1>{count}</h1>
      <button onClick={e => setCount(c => c + 1)}>+1</button>
      <ChildComponent fn={fn}/>
    </>
  )
}


ReactDOM.render(<ParentComponent />,  document.getElementById('root'));
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值