Hacker News new | ask | show | jobs
by jdjb 1693 days ago
If you're using React.useCallback to avoid triggering further hooks down the line, then you're using it wrong. Since React.useCallback is ostensibly just React.useMemo wrapped around a function, this note in the documentation is just as applicable:

  You may rely on useMemo as a performance optimization, not as a semantic guarantee. In the future, React may choose to “forget” some previously memoized values and recalculate them on next render, e.g. to free memory for offscreen components. Write your code so that it still works without useMemo — and then add it to optimize performance.
3 comments

You're only using it wrong if you're trying to avoid triggering hooks as something other than a performance optimization.

For example, something like this should work correctly even without useCallback, but you would be constantly re-subscribing for no good reason.

    const callback = useCallback(...);

    useEffect(() => {
        const unsubscribe = subscribe(callback);
        return () => unsubscribe();
    }, [callback]);
I was following a pattern similar to react-table, where I'm destructuring a function off of a previous hook and passing it to another hook as a callback. This allows the 2nd hook to update state in the first, which causes it to infinite loop if the function isn't wrapped. I think this pattern is more complicated than it sounds, but really helps to remove business logic from a component
If we have a component <ProfilePage id={id} onLoad={handleOnLoad} /> and inside profile page we use an effect to load from id and call handleOnLoad with the loaded profile data, then we need to put handleOnLoad in the useEffect dependencies. So we have to pass a callback wrapped in useCallback else the effect would fire every time ProfilePage rerenders.