A year of React but I still get render loops I don't know how to fix in situations like:
- A parent passes a onFinish prop to a child
- The child calls the onFinish function at some point
- onFinish changes something that causes a re-render
Conversation
(This becomes more complicated when intermediate components between that parent and child wrap onFinish into their own onFinish function that's passed down. Same problem but more steps makes it much more confusing.)
1
1
6
It seems like the thing to do here is to useCallback every callback that's passed down? But the Hooks API Reference (reactjs.org/docs/hooks-ref) doesn't even talk about using it like that; it talks about it only in terms of optimization.
5
10
It seems like useCallback roughly doubles the code size whenever I do it. Here's an actual screenshot of what it takes to satisfy the linter with and without useCallback. This is the actual example that prompted these tweets.
6
1
12
Yes, I've found that in practice useCallback is necessary for most upward-control-flow situations. Agreed on the code size challenges! Usually, though, it doesn't make sense to re-render when callbacks change, so you can use weak callbacks: gist.github.com/andymatuschak/
2
7
In this approach, the HTMLButtonElement (or whatever) gets assigned a callback that doesn't change over time, but that callback closes over an object (the ref) whose field (current) changes to the latest function literal whenever the hook's parent is dirtied.
1
Interesting. I haven't tried this in code, but I can imagine situations where this would genuinely violate the dependencies that should be in place. E.g. if you conditionally define a callback to be one function body or another, then pass it down. Right?
2
Not sure if this is what you’re describing but I think there’s a pitfall when calling handleFinish3 before useEffect (eg render or useLayoutEffect) jsfiddle.net/nvkroeyj/
1
Ah, yes, that’s true! I only use this approach for event handlers, but you’d definitely run into timing issues if you call one of these callbacks during the React update cycle.
1
(I suppose you could just update ref.current in render() directly, rather than via useEffect…)


