目录
React.useCallback(function,array)
返回一个函数,只有在array中的依赖项变化的时候才会更新(返回一个新的函数)。
使用场景:当父组件传入子组件函数时,由于React.memo进行的是浅比较,重新渲染时,函数的引用是发生改变的,所以会导致子组件重新渲染,而用useCallback后只要依赖的变量未发生改变将始终返回同一个函数引用,不会导致子组件重新渲染。
注意区别于useMemo 缓存的是函数的返回结果。useCallback缓存的是函数。
点击 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}>Button1Button>
- div>
- <div>
- <Button onClickButton={handleClickButton2}>Button2Button>
- div>
- <div>
- <Button onClickButton={() => {setCount3(count3 + 1); }}>
- Button3
- Button>
- div>
- div>
- );
- }
- const rootElement = document.getElementById("root");
- ReactDOM.render(<App />, rootElement);
下面先点击弹框按钮再点击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}>Followbutton>;
- }
- }
- function FunctionProfilePage(props) {
- const showMessage = () => {
- alert('Followed ' + props.user);
- };
- const handleClick = () => {
- setTimeout(showMessage, 3000);
- };
- return (
- <button onClick={handleClick}>Followbutton>
- );
- }
- function App() {
- const [state,setState] = useState(1);
- return (
- <div className="App">
- <button onClick={() => {
- setState(x => x+x);
- }}>doublebutton>
- <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);
- });
- }
可以通过下面修改在类组件中打印快照值。
- 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);
- };