React useCallback 参考问题和闭包。 usecallback 在渲染上重新创建

问题描述 投票:0回答:1
import React, { useCallback, useState } from 'react';

const App = () => {
  const [count, setCount] = useState(0);

  const increase = useCallback(() => {
    let count = null;
    function incrementByOne() {
      count = count + 1;
      console.log(count);
    }
    return incrementByOne;
  }, []);

  return (
    <>
      <button onClick={() => setCount(count + 1)}>{count}</button>
      <button onClick={increase()}>Increase</button>
    </>
  );
};

export default App;

从上面的代码中,当我单击“增加”按钮(第二个)时,计数增加一并对其进行控制台,并且它不会重新渲染,但是当我单击第一个按钮时状态值发生变化并且组件呈现,然后当我单击第二个按钮时计数从 1 开始,重新渲染后,前一个计数初始化为零,即使使用 useCallback 重新渲染时的增加方法重新创建,任何人都可以解释为什么该值在渲染和 useCallback 再次重新创建后不持久

javascript reactjs closures
1个回答
0
投票

问题不在于

useCallback
返回不同的函数。当您的组件由于状态更改而重新渲染时,您将再次调用
increase()
,在新的
incrementByOne
上创建新的
count
闭包。您可以通过在
console.trace('re-initialising count')
正上方的
increase
中添加
let count = null;
来看到这一点。

要解决此问题,您需要确保仅在安装组件时创建闭包一次,而不是在每次渲染时创建闭包。可以使用

useMemo()
,但更可靠的解决方案是使用
useState
的初始化程序功能,只是从不更新状态:

function App() {
  const [count, setCount] = useState(0);

  const [increment, _] = useState(() => {
    let count = 0;
    return () => {
      count = count + 1;
      console.log(count);
    };
  });

  return (
    <>
      <button onClick={() => setCount(count + 1)}>{count}</button>
      <button onClick={increment}>Increase</button>
    </>
  );
}

但是,惯用的 React 方法1 将完全避免闭包和可变变量,而是使用 ref:

function App() {
  const [count, setCount] = useState(0);

  const countRef = useRef(0);
  const increment = () => {
    countRef.current = countRef.current + 1;
    console.log(countRef.current);
  };

  return (
    <>
      <button onClick={() => setCount(count + 1)}>{count}</button>
      <button onClick={increment}>Increase</button>
    </>
  );
}

1:或者说真的,你不应该在不重新渲染的情况下改变任何东西,所以你可以只使用正常状态......

© www.soinside.com 2019 - 2024. All rights reserved.