React.useCallback(function,array)使用,React中的函数组件和类组件的取值(快照or最新值)

目录

React.useCallback(function,array)

React.memo

示例1

示例2

React中的函数组件和类组件的取值(快照or最新值)

闭包例子

修改React例子


React.useCallback(function,array)

返回一个函数,只有在array中的依赖项变化的时候才会更新(返回一个新的函数)。

使用场景:当父组件传入子组件函数时,由于React.memo进行的是浅比较,重新渲染时,函数的引用是发生改变的,所以会导致子组件重新渲染,而用useCallback后只要依赖的变量未发生改变将始终返回同一个函数引用,不会导致子组件重新渲染。

注意区别于useMemo 缓存的是函数的返回结果useCallback缓存的是函数

React.memo

React纯组件pureComponent、React.memo(FunComponent,compareFunction)、React.useMemo(callback,array)_YF-SOD的博客-CSDN博客

示例1

点击 Button1 的时候只会更新 Button1 和 Button3 后面的内容;

点击 Button2 会将三个按钮后的内容都更新;

点击 Button3 的也是只更新 Button1 和 Button3 后面的内容。

没有用useCallback包括的函数,每次都会重新声明一个新的方法,新的方法尽管和旧的方法一样,但是依旧是两个不同的对象,React.memo对比后发现对象props改变,就重新渲染了。而用uesCallback包括的函数只有当依赖项改变时才会返回新的函数(对象),所以不会重新渲染。

const Button = React.memo(({ onClickButton, children }) => {
  return (
    <>
      <button onClick={onClickButton}>{children}</button>
      <span>{Math.random()}</span>
    </>
  );
});
export default function App() {
  const [count1, setCount1] = useState(0);
  const [count2, setCount2] = useState(0);
  const [count3, setCount3] = useState(0);
  const handleClickButton1 = () => {setCount1(count1 + 1);}
  const handleClickButton2 = useCallback(() => {
    setCount2(count2 + 1);
  }, [count2]);

  return (
    <div>
      <div>
        <Button onClickButton={handleClickButton1}>Button1</Button>
      </div>
      <div>
        <Button onClickButton={handleClickButton2}>Button2</Button>
      </div>
      <div>
        <Button  onClickButton={() => {setCount3(count3 + 1);     }}>
          Button3
        </Button>
      </div>
    </div>
  );
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

示例2

useCallback - 简书

React中的函数组件和类组件的取值(快照or最新值)

下面先点击弹框按钮再点击double,alert中的数值,在类组件中始终显示的是最新的。而在函数组件中始终显示的是点击弹框时的数值(快照)而不是double后的数值。

import React, { useState } from "react";
class ClassProfilePage extends React.Component<any,any> {
  showMessage = () => {
    alert('Followed ' + this.props.user);
  };
  handleClick = () => {
    setTimeout(this.showMessage, 3000);
  };
  render() {
    return <button onClick={this.handleClick}>Follow</button>;
  }
}
function FunctionProfilePage(props) {
  const showMessage = () => {
    alert('Followed ' + props.user);
  };
  const handleClick = () => {
    setTimeout(showMessage, 3000);
  };
  return (
    <button onClick={handleClick}>Follow</button>
  );
}
function App() {
  const [state,setState] = useState(1);
  return (
    <div className="App">
      <button onClick={() => {
        setState(x => x+x);
      }}>double</button>
      <div>state:{state}</div>
      <FunctionProfilePage user={state} /> // 点击始终显示的是快照值
      <ClassProfilePage user={state} /> // 点击始终显示的是最新值
    </div>
  );
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

理解为在类组件中是挂载在this的引用上所以始终拿到的是最新的值,而在函数组件中是最新值。 

闭包例子

for(var i=0;i<10;i++){
    setTimeout(() => console.log('val:',i)) // 拿到的是最新值
}

for(var i=0;i<10;i++){
    setTimeout(((val) => console.log('val:',val)).bind(null,i)); // 拿到的是快照
}

const ref = {current: null}
for(var i=0;i<10;i++){
    ref.current = i; 
    setTimeout(((val) => console.log('val:',ref.current)).bind(null,ref)); // 拿到的是最新值
}

for (var i = 0; i < 10; i++) { // 拿到的是快照
    let t = i;
    setTimeout(() => {
        console.log("t:", t);
    });
}

修改React例子

可以通过下面修改在类组件中打印快照值。

  showMessage = (message) => {
    alert('Followed ' + message);
  };
  handleClick = () => {
   const message = this.props.user // 在触发异步函数之前保存快照
   setTimeout(()=>{this.showMessage(message)}, 3000);
  };

可以通过下面修改在函数组件中打印最新值(ref存取最新值)。

const ref = useRef("");
useEffect(() => {
  ref.current = props.user;
});
const showMessage = () => {
  console.log('ref:',ref)
  alert("Followed " + props.user +',' + ref.current);
};

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值