React useMemo的使用

87 阅读1分钟

React.memo

首先我们先来了解一下 React.memo

import React, { useState } from "react";
import "./styles.css";

export default function App() {
  const [n,setN] = useState(0)
  const [m,setM] = useState(0)
  const addN=()=>{
    setN(i=>i+1)
  }
  const addM=()=>{
    setM(i=>i+1)
  }
  return (
    <div className="App">
      <h1>n:{n}</h1>
      <Child value={m}/>
      <button onClick={addN}>n+1</button>
      <button onClick={addM}>m+1</button>
    </div>
  );
}

const Child =(props)=> {
  console.log('Child 执行了')
  return <h1>m:{props.value}</h1>;
}

效果

例子中,当 nm 变化时,因为<App>重新渲染, 所以Child 函数重新执行,使用 React.memo 我们再来看看

import React, { useState } from "react";
import "./styles.css";

export default function App() {/*其他代码*/}
const Child =React.memo((props)=> {
  console.log('Child 执行了')
  return <h1>m:{props.value}</h1>;
});

效果 可以看出,当n变化时函数 Child 没有执行,而当 m 变化时,函数 Child 执行了,因此,我们可以把props没有改变的而执行的函数放入React.memo中,可以优化组件,解决函数重复执行,降低效率问题

但是,React.memo有一个 bug,我们来看下面的例子

import React, { useState } from "react";
import "./styles.css";

export default function App() {
  const [n,setN] = useState(0)
  const [m,setM] = useState(0)
  const addN=()=>{
    setN(i=>i+1)
  }
  const addM=()=>{
    setM(i=>i+1)
  }
  const ClickChild=()=>{}
  return (
    <div className="App">
      <h1>n:{n}</h1>
      <Child value={m} onClick={ClickChild}/>
      <button onClick={addN}>n+1</button>
      <button onClick={addM}>m+1</button>
    </div>
  );
}
const Child =React.memo((props)=> {
  console.log('Child 执行了')
  return <h1 onClick={props.onClick}>m:{props.value}</h1>;
});

效果

可以看到,当n变化时函数 Child 又执行了,这是为什么呢?原因是:当 <App>重新渲染,const ClickChild=()=>{} 重新执行,于是 ClickChild 的地址已经和上一次的不同了,因此函数 Child 执行了

于是我们就需要用到 useMemo了,

useMemo

useMemo 的第一个函数是 ()=>value,第二个参数是依赖 [m],该 Hook 可以缓存函数的返回值,避免函数不必要的调用,导致组件的重新渲染

/*其他代码*/

const ClickChild=useMemo(()=>{
    return ()=>{}
  },[m])
  
/*其他代码*/

效果

注意: 如果你的 value 是一个函数的话,则要写成 useMome(()=>x=>coonsole.log(x),[m]),由于太难用,于是就有了语法糖 useCallback,即可以改写成 useCallback(x=>coonsole.log(x),[m])