memo、useMemo和useCallback的区别

memo用来优化函数组件的重复渲染行为,当传入属性值都不变的情况下不会触发组件的重新渲染,否则就会触发组件的重新渲染;和类组件的PureComponent的功能是类似的;在hooks环境下,几乎所有组件都是函数式组件,我们使用memo的几率要比PureComponent高得多;

const ExpensiveComponent = React.memo(() => {
  console.log('Expensive Component Rendered');
  let total = 0;
  for (let i = 0; i < 1000000000; i++) {
    total += i;
  }
  return <div>Expensive Component</div>
})

export default ExpensiveComponent;

memo针对的是一个组件的渲染是否重复执行,而useMemo则定义了一段函数逻辑是否重复执行
本质都是用同样的算法来判定依赖是否发生改变,继而决定是否触发特定逻辑;(有很多这样的逻辑:输入和输出是对等的,相同的输入一定产生相同的输出,数学上称之为幂等)利用memo就可以避免不必要的重复计算,减少资源浪费。

所以严格来讲,不使用memo和useMemo不应该会导致你的业务逻辑发生变化(memo和useMemo只是用来做性能优化)​

import { useEffect, useMemo } from "react";

function App () {
  const [name, setName] = useState('');
  const [age, setAge] = useState(null);
  const [country, setCountry] = useState('');

  const userType = useMemo(() => ({
    underAge: age < 18 ? true : false,
    citizen: country === 'USA' ? true : false
  }), [age, country]);

  useEffect(() => {
    console.count("User type has changed");
  }, [userType]);

  console.log("Component re-rendered")

  return (
    <div>
      <input type="text" value={name} onChange={e => setName(e.target.value)} />
      <input type="number" value={age} onChange={e => setAge(e.target.value)} />
      <input type="text" value={country} onChange={e => setCountry(e.target.value)} />
    </div>
  )
}

useMemo和useEffect的语法是一样的,第一个参数是要执行的逻辑函数,第二个参数是这个逻辑函数依赖的变量组成的数组,如果不传第二个参数,则useMemo的逻辑函数每次都执行,那useMemo的意义就不存在了。如果传入空数组,则只执行一次;

useMemo和useEffect的执行时机是不一致的:useEffect执行的是副作用,所以一定是在渲染之后执行的,useMemo是需要有返回值的,而返回值可以直接参与渲染的,所以useMemo是在渲染期间完成的,有这样一个一前一后的区别

userMemo和useCallback接受的参数都是一样的,第一个参数为回调函数,第二个参数是要依赖的数据;

共同点:只有在依赖数据发生变化后,才会重新计算结果,起到缓存的作用

区别:useMemo返回的是计算的结果值,用于缓存计算后的状态
useCallback返回的是函数,主要用来缓存函数,因为函数式组件中的state的变化都会导致整个组件被重新刷新(即使一些函数没有必要被刷新),此时用useCallback就会将函数进行缓存,减少渲染时的性能损耗​;

import { useEffect } from "react";

export default function UseCallbackPage () {
  const [count, setCount] = React.useState(0);
  // 不加 useCallback,input框输入事件也会触发ChildMemo组件重新渲染;利用 useCallback缓存 addClick 函数,并添加 count 作为依赖项,可以解决子组件重新渲染问题
  const handleClick = React.useCallback(() => {
    let sum = 0;
    for (let i = 0; i < 1000000000; i++) {
      sum += i;
    }
    return sum;
  }, [count]);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
      <input value={value} onChange={(event) => setValue(event.target.value)} />
      <ChildMemo onClick={handleClick} />
    </div>
  );
}

// ChildMemo component is wrapped with React.memo to prevent unnecessary re-renders
const ChildMemo = React.memo(({ onClick }) => {
  useEffect(() => {
    return () => {
      console.log("Child component unmounted");
    }
  }, []);

  console.log("Child component rendered");
  return <button onClick={() => console.log(onClick())}>Click me</button>;
})
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值