Hooks中的useMemo

Memo

理解React.useMemo前要先理解React.Memo
先看代码:

import React from "react";
function App(){
    const [n,setN] = React.useState(0);
    const [m,setM] = React.useState(0);
    const onClick = () => {
        setN(n+1)
    }
return (
    <div>
        <div>
        <button onClick={onClick}>update n {n}</button>
        </div>
        <Child data={m}/>
    </div>
)
}
function Child(props) {
    console.log('child执行了');
    return <div>
        child: {props.data}
    </div>
}
export default App
复制代码

渲染结果如下所示,点击按钮update n时,虽然child的值不影响,但是child组件里的log还是被打印出来了。

react2.gif
Child用React.memo(Child)代替就好了,代码如下:

import React from "react";
function App(){
    const [n,setN] = React.useState(0);
    const [m,setM] = React.useState(0);

    const onClick = () => {
        setN(n+1)
    }
    const onClick2 = () => {
        setM(m+1)
    }

return (
    <div>
        <div>
        <button onClick={onClick}>update n {n}</button>
        <button onClick={onClick2}>update m {m}</button>
        </div>
        <Child2 data={m}/>
    </div>
)
}
function Child(props) {
    console.log('child执行了');
    return <div>
        child: {props.data}
    </div>
}
const Child2 = React.memo(Child)
export default App
复制代码

渲染结果如下,当m值改变后才会log

react2.gif

Memo的bug

当添加了监听函数之后,Child组件的log又执行了,代码如下:

import React from "react"
export default function App() {
    console.log('app执行了');
    const [n, setN] = React.useState(0);
    const [m, setM] = React.useState(0);
    const onClick = () => {
      setN(n + 1);
    };
    const onClickChild = () => {
      console.log(m);
    };
    return (
      <div className="App">
        <div>
          <button onClick={onClick}>update n {n}</button>
        </div>
        <Child2 data={m} onClick={onClickChild} />
        {/* Child2 居然又执行了 */}
      </div>
    );
  }
  
  function Child(props) {
    console.log("child 执行了");
    return <div onClick={props.onClick}>child: {props.data}</div>;
  }
  
  const Child2 = React.memo(Child);
复制代码

渲染结果如下:

react2.gif
出现以上结果是因为,App运行时会再次执行onClickChild,生成新的函数,新旧函数功能虽然一样,但是地址时不同的,那只能用useMemo了。

useMemo

useMemo的特点:

  • 第一个参数是() => value
  • 第二个参数是依赖[m,n]
  • 只有依赖变化时,才会计算除新的value
  • 如果依赖不变,就会重用之前的value

有没有很像Vue2中的computed?
通过useMemo改动上面的例子:

import React from "react"
export default function App() {
    const [n, setN] = React.useState(0);
    const [m, setM] = React.useState(0);
    const onClick = () => {
      setN(n + 1);
    };
   const onClickChild = React.useMemo(()=>{
    return ()=>{
        console.log(m);
    }
   },[m])
    return (
      <div className="App">
        <div>
          <button onClick={onClick}>update n {n}</button>
        </div>
        <Child2 data={m} onClick={onClickChild} />
      </div>
    );
  }
  
  function Child(props) {
    console.log("child 执行了");
    return <div onClick={props.onClick}>child: {props.data}</div>;
  }
  const Child2 = React.memo(Child);
复制代码

渲染结果如下,只有m变化了才会触发Child组件log

react2.gif

useCallback

在useMemo中,如果value是个函数,那么就要写成useMemo(()=>(x)=>console.log(x)),这是一个返回函数的函数,有点难用,于是就出现了useCallback

useCallback与useMemo是等价的,用法不同,如:
useCallback(x=>log(x),[m]) 等价于 useMemo(()=>x=>log(x),[m])

用useCallback改写以上例子:

import React from "react"
export default function App() {
    const [n, setN] = React.useState(0);
    const [m, setM] = React.useState(0);
    const onClick = () => {
      setN(n + 1);
    };
    
   const onClickChild = React.useeCallback(()=>{
    console.log(m);
  },[m])

    return (
      <div className="App">
        <div>
          <button onClick={onClick}>update n {n}</button>
        </div>
        <Child2 data={m} onClick={onClickChild} />
      </div>
    );
  }
  
  function Child(props) {
    console.log("child 执行了");
    return <div onClick={props.onClick}>child: {props.data}</div>;
  }
  const Child2 = React.memo(Child);
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享