zlx362211854 / daily-study

每日一个知识点总结,以issue的形式体现
10 stars 6 forks source link

82. useCallback vs useMemo #131

Open goldEli opened 5 years ago

goldEli commented 5 years ago

useCallback, useMemo 有什么用?

nanslee commented 5 years ago

useMemo 和 useCallback 都会在组件第一次渲染的时候执行,之后会在其依赖的变量发生改变时再次执行;并且这两个 hooks 都返回缓存的值,useMemo 返回缓存的变量,useCallback 返回缓存的函数 useMemo(() => fn, []) 等价于 useCallback(fn, [])

例子:

// index.js 
import React, { useState } from "react";
import Child from './child';
import ReactDOM from "react-dom";

import "./styles.css";

function App() {
  const [name, setName] = useState('o1wish');
  const [time, setTime] = useState('null');
  return (
    <div>
      <button onClick={() => setName('xxx')}>改名</button>
      <br />
      <button onClick={() => setTime(new Date().getTime())}>改时间</button>
      <br />
      <Child name={name} time={time}>{time}</Child>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

// child.js
import React from 'react';

export default props => {
  const changeName = name => {
    console.log('changeName触发');
    return 'name变更为: ' + name;
  }

  const otherName = changeName(props.name)
  return <>
    <div>{otherName}</div>
    <div>{props.time}</div>
  </>
}

image

// child.js
import React, {useMemo} from 'react';

export default props => {
  const changeName = name => {
    console.log('changeName触发');
    return 'name变更为: ' + name;
  }

  const otherName = useMemo(() => changeName(props.name), [props.name])
  return <>
    <div>{otherName}</div>
    <div>{props.time}</div>
  </>
}

image

goldEli commented 5 years ago

useCallback

避免函数组件内的方法重复初始化

const memoizedCallback = useCallback(() => {
 doSomething(a, b)   
}, [a, b])

useMemo

避免需要大量计算的组件,重复计算

const memoizedValue = useMemo(() => {
 return computeExpensiveValue(a, b)    
}, [a, b])

总结

这两个方法都是用来优化性能的,用空间换时间。

使用策略:如果没有必要,尽量避免使用,会增加维护成本

zlx362211854 commented 5 years ago

补充一点,useCallback和useMemo是锦上添花的功能,官网中有句话:

You may rely on useMemo as a performance optimization, not as a semantic guarantee. In the future, React may choose to “forget” some previously memoized values and recalculate them on next render, e.g. to free memory for offscreen components. Write your code so that it still works without useMemo — and then add it to optimize performance.

意思就是说,我们在使用上述两个hooks的时候,需要先保证不使用它们时也能正常渲染,因为这两个hooks所做的缓存,可能会在其他时间,比如离屏渲染的时候被释放掉,所以写代码的逻辑是:先写正常代码,测试通过再做优化。