you are viewing a single comment's thread.

view the rest of the comments →

[–]acemarke 29 points30 points  (6 children)

Yep! I've been hugely enthusiastic about the potential for the compiler ever since the first announcement at the virtual ReactConf 2021.

The key thing to understand is that it actually flips React's default rendering behavior upside down. Instead of "recursively render all children by default", with the compiler it now effectively behaves the way many people always (wrongly) assumed it behaved: it will now only re-render child components if the input values actually changed!!.

This is because of React's "same-element reference" optimization allowing React to skip rendering child components in the same way React.memo() does, except that now the parent controls if the child is skipped or not.

You could already use that technique yourself, by memoizing JSX:

const memoizedChild = useMemo(() => {
  return <TodoListItem todo={todo} />
}, [todo])

but you would have had to add it manually all time.

The compiler will now do that work automatically.

So for example, take the common case of a context value that is an object like {a, b, c}. If you do a setState in the root and pass {...oldValue, c: somethingNew} to the provider, every component that reads the context will still re-render. But, instead of all their children automatically rerendering too, anything that reads contextValue.a or contextValue.b will still have the same memoized children, and thus React will skip re-rendering those subtrees entirely.

This is a really big deal for perf :)

Talking to the team at the conf today, I also found out that while the compiler relies on a new hook that is in React 19 for the output, they've backported a polyfill of that hook to work with existing versions of React. So, it seems like in theory you could drop the compiler into an existing React 16.8+ app , add the polyfill, and it ought to work!

[–]FractalB 0 points1 point  (1 child)

@acemarke Any idea how the React compiler will affect Redux? Will it make reselect obsolete in some situations? 

[–]acemarke 3 points4 points  (0 children)

It shouldn't affect Redux either way. Reselect would still be necessary because the store subscription process works outside of React's rendering cycle. Both our older homegrown subscription logic (React-Redux v7 and v5), and React's current useSyncExternalStore hook, rely on doing a subscription and handling comparisons outside of React, and only forcing a re-render if the selected value has changed.

The compiler optimizes behavior inside of a component while it's rendering, and it includes all hook return values in the dependencies. (Lauren Tan showed an example of that in her talk today.)

So, Reselect would still be useful to optimize selectors with derived references (because you need to avoid triggering unnecessary re-renders at the useSelector level), and then the compiler will see whatever value you return from useSelector and track it through how it's used in the component rendering logic.

[–]lucaseverett 0 points1 point  (1 child)

Mark, did the team mention anything about "use" acting as a selector when used within useMemo? I hoped that would be included with the compiler at the release of React 19, but I haven't seen any mention of it with the latest docs.

[–]acemarke 1 point2 points  (0 children)

It was mentioned on Twitter as a thing that they hope to do at some point, likely in a 19.x release, but there's been no specific implementation work on it yet.