React

useMemo

2022-11-04  本文已影响0人  未路过

它和useCallback一样,也是返回有记忆的值。


image.png
import React, { memo, useState } from "react";

function calcNumTotal(num) {
  console.log("calcNumTotal被执行");
  let total = 0;
  for (let i = 1; i < num; i++) {
    total += i;
  }
  return total;
}

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

  return (
    <div>
      <h2>计算结果:{calcNumTotal(50)}</h2>
      <h2>count:{count}</h2>
      <button onClick={(e) => setCount(count + 1)}>点我加1</button>
    </div>
  );
});

export default App;

每一次点击button, <h2>计算结果:{calcNumTotal(50)}</h2>就会被重新渲染,calcNumTotal函数会被执行。50并没有改变,所以没必要反复地被进行调用
这样给定义一个total变量的化,不会被反复执行

import React, { memo, useState } from "react";

function calcNumTotal(num) {
  console.log("calcNumTotal被执行");
  let total = 0;
  for (let i = 1; i < num; i++) {
    total += i;
  }
  return total;
}

let total = calcNumTotal(50);

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

  return (
    <div>
      <h2>计算结果:{total}</h2>
      <h2>count:{count}</h2>
      <button onClick={(e) => setCount(count + 1)}>点我加1</button>
    </div>
  );
});

export default App;

但是把total定义在组件外面,再去使用,不合适,而且total直接写死了。
把total定义在App里面,也是会被反复的调用。

import React, { memo, useState } from "react";

function calcNumTotal(num) {
  console.log("calcNumTotal被执行");
  let total = 0;
  for (let i = 1; i < num; i++) {
    total += i;
  }
  return total;
}

const App = memo(() => {
  const [count, setCount] = useState(0);
  let total = calcNumTotal(50);

  return (
    <div>
      <h2>计算结果:{total}</h2>
      <h2>count:{count}</h2>
      <button onClick={(e) => setCount(count + 1)}>点我加1</button>
    </div>
  );
});

export default App;

这个时候就可以使用useMemo。useMomo传入一个函数,他优化的是这个函数的返回值。

  let result = useMemo(() => {
    return calcNumTotal(50);
  }, []);

用useMemo对返回结果做一个优化。
第二个传入空数组代表对什么都不依赖。
如果依赖count,[count]代表count改变,我里面的函数再重新执行。
写空数组代表我useMomo里面的函数和谁都没有关系,这个函数不会被重新调用。返回的result永远是同一个值。

useMemo 和 useCallback的对比


  function fn() {
    console.log("increment");
    setCount(count + 1);
  }

  const increment = useCallback(fn, []);
  const increment2 = useMemo(() => fn, []);
  /* 这两个写法相同。对什么都没有依赖的时候,返回的值incrment都相同。一个是直接对函数做优化,一个是对函数的返回结果做优化 */

当count发生改变的时候,useMemo里面的函数重新执行,返回不同的结果。count改变的时候,里面的函数才会做一个执行。

  let result = useMemo(() => {
    return calcNumTotal(count * 2);
  }, [count]);

总结1:

1.如果函数里面有大量的计算,每次render的时候使用结果,useMemo对这个函数要不要重新执行进行优化。用useMemo包裹的化,不对任何进行依赖,是不会反复执行这个函数的,一直使用同一个值。

如果把这两个传递给子组件,会不会有区别


image.png

<HelloWorld result={result}></HelloWorld>
其实没有区别,因为子组件传递的都是一个数字。
如果是calcNumTotal(50) 那么子组件只有渲染一次,因为这个结果是一定的,而且子组件用了memo包裹。这个时候无论是有没有用useMomo包裹这个函数,子组件都是不会被渲染的。
但是如果是calcNumTotal(count * 2),子组件是每次都会被渲染的。

以上都是没有区别的。
以下情况会有区别

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

const HelloWorld = memo(function (props) {
  console.log("hellow");
  return <h2>HelloWorld</h2>;
});

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

  const info = { name: "why", age: 18 };
  return (
    <div>
      <h2>count:{count}</h2>
      <button onClick={(e) => setCount(count + 1)}>点我加1</button>
      <HelloWorld infp={info}></HelloWorld>
    </div>
  );
});

export default App;

当count发生改变的时候,子组件会重新渲染。当app函数重新执行,const info ={}会重新定义一个新的对象,如果不希望重新给子组件渲染,就使用useMemo包裹

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

const HelloWorld = memo(function (props) {
  console.log("hellow");
  return <h2>HelloWorld</h2>;
});

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

  const info = useMemo(() => ({ name: "why", age: 18 }), []);
  return (
    <div>
      <h2>count:{count}</h2>
      <button onClick={(e) => setCount(count + 1)}>点我加1</button>
      <HelloWorld infp={info}></HelloWorld>
    </div>
  );
});

export default App;

总结2

对子组件传递相同内容的对象时候,使用useMemo可以进行性能优化。不让子组件进行多次渲染!(传入值是没有去别的,用memo包裹的话,子组件是不会重新渲染的)

优化的点是2个!!!!
useCallback就是只有1个,给子组件传递一个函数的时候进行性能优化!!不让子组件进行多次渲染!

上一篇 下一篇

猜你喜欢

热点阅读