react中useMemo的两个使用场景

260 阅读1分钟

useMemo是react中常被用来进行性能优化的hook,其原理是通过将函数,组件,变量等缓存,防止状态改变发生重渲染而导致的重复计算。所以本质上是将某一个值保存在内存中,重复渲染时可以避免重复大量的计算以及保证了值的一致性

第一种使用场景,缓存高计算量的内容

function App() {
  const [number, setNumber] = useState(0)
  const [dark, setDark] = useState(false)
  const doubleNumber = slowFunction(number)


  const themeStyles = {
     backgroundColor: dark ? 'black' : 'white',
     color:dark?'white':'black'
  }

  useEffect(() => {
    console.log('theme change')//做出一些提示等
  }, [themeStyles])
  
  return (
    <div className="App">
      <input type="number" value={number} onChange={e => setNumber(parseInt(e.target.value))}/>
      <button onClick={()=>setDark(prevDark=>!prevDark)}>Change Theme</button>
      <div style={themeStyles}>{ doubleNumber}</div>
    </div>
  );
}

export default App;

function slowFunction(num) {
  console.log('Calling Slow Function')
  for (let i = 0; i <= 10_0000_0000; i++){ }
  return num*2
}
  

如上图代码,当我们对setNumber时,重渲染会导致doubleNumber通过调用slowFunction进行赋值,而slowFunction时一个很耗时的操作。由于doubleNumber依赖number的变化,所以在这里的耗时操作是正常必需的,可以想象为一个网络请求等。但是当我们点击按钮切换主题时,也会导致重渲染,而number并没有发生改变,所以doubleNumber也不用变化,此时再调用slowFunction是耗时且不必要的。可以将doubleNumber使用useMemo封装,可以避免主题改变时的重复计算

  const doubleNumber = useMemo(() => {
    return slowFunction(number)
  },[number])

第二种使用场景,需要保持一致性,防止不必要的Effect

修改了doubleNumber的重复计算问题后,上述代码还有一个问题。就是主题改变时,useEffect会产生回调。但是当我们修改number时,发生了重渲染,此时重新运行渲染函数,useEffect同样会产生回调。原因就是,虽然渲染前后themeStyles对象里的内容一致,但是实际上是不同的两个对象,所以useEffect检测到themeStyles引用的对象发生改变后,产生回调。同样可以通过useMemo缓存themeStyles对象来避免不正常的Effect

  const themeStyles = useMemo(() => {
    return {
      backgroundColor: dark ? 'black' : 'white',
      color:dark?'white':'black'
    };
  },[dark])

结束语