我不明白为什么useCallback
每次更新一个 deps 时总是返回一个新的 ref。它导致许多重新渲染 React.memo()
本来可以避免的。useCallback
的这个实现有什么问题(如果有的话) ?
export function useCallback(callback) {
const callbackRef = useRef();
callbackRef.current = callback;
return useState(() =>
(...args) => callbackRef.current(...args)
)[0];
}
使用它而不是内置实现肯定会对性能产生重大的积极影响。自己的结论:
没有理由不使用使用 ref 的实现而不是内置的 只要您知道其中的含义,即正如@Bergy 所指出的那样,您就不能存储回调以供以后使用(例如,在
setTimeout
之后)并期望回调具有与 if 相同的效果你会同步调用它。然而,在我看来,这是首选行为,所以没有缺点🥂。
更新:
有一个 React RFC 用于引入一个内置的钩子(Hook)来做到这一点。它将被称为 useEvent
最佳答案
What is, if any, the problem with this implementation of
useCallback
?
我怀疑当有人存储对您的回调的引用以供以后使用时,它会产生意想不到的后果,因为它会改变它正在做的事情:
const { Fragment, useCallback, useState } = React;
function App() {
const [value, setValue] = useState("");
const printer = useCallback(() => value, [value]);
return <div>
<input type="text" value={value} onChange={e => setValue(e.currentTarget.value)} />
<Example printer={printer} />
</div>
}
function Example({printer}) {
const [printerHistory, setHistory] = useState([]);
return <Fragment>
<ul>{
printerHistory.map(printer => <li>{printer()}</li>)
}</ul>
<button onClick={e => setHistory([...printerHistory, printer])}>Store</button>
</Fragment>
}
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://unpkg.com/react@16.14.0/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@16.14.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>
(当然,在这个简化的演示中,
printer
回调只不过是对 value
本身的无用闭包,但您可以想象一个更复杂的情况,即可以选择一个单独的历史条目并希望使用复杂的 on-回调中的需求计算)与原生
useCallback
,函数存储在printerHistory
将是对不同值的不同闭包,而在您的实现中,它们都是引用最新 useCallback
的相同函数参数并且仅在每次调用时打印当前值。
关于javascript - 为什么 `useCallback` 不能总是返回相同的 ref,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65890278/