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 再次重新创建后不持久
问题不在于
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:或者说真的,你不应该在不重新渲染的情况下改变任何东西,所以你可以只使用正常状态......