Why can't `useCallback` always return the same ref

Jos*_*one 8 javascript reactjs react-hooks usecallback

I don't understand why useCallback always returns a new ref each time one of the deps is updated. It results in many re-render that React.memo() could have avoided.

What is, if any, the problem with this implementation of useCallback?

export function useCallback(callback) {

    const callbackRef = useRef();

    callbackRef.current = callback;

    return useState(() =>
        (...args) => callbackRef.current(...args)
    )[0];

}
Run Code Online (Sandbox Code Playgroud)

Using this instead of the built-in implementation sure has a significant positive impact on performance.

Own conclusion:

There is no reason not to use an implementation using ref over the built's in as long as you are aware of the implications, namely, as pointed out by @Bergy, you can't store a callback for use later (after a setTimeout for example) and expect the callback to have the same effect as if you'd have called it synchronously.
In my opinion however this is the preferred behaviour so no downside .

Ber*_*rgi 5

如果有的话,这个实现有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'));
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

(当然,在这个简化的演示中,printer回调只不过是对value自身的无用闭包,但您可以想象一个更复杂的情况,在这种情况下,人们可以选择单个历史记录条目,并希望在回调中使用复杂的按需计算)

对于 native useCallback,存储在 中的函数printerHistory将是不同值的不同闭包,而在您的实现中,它们都将是引用最新useCallback参数的相同函数,并且只在每次调用时打印当前值。