5 min read
All the pieces React is getting rid of with its new Compiler

We don’t need any manual memoization anymore

How state update happens causing a re-render tree

React has two internal states. One that we consume, and one which is used to update the state (to hold the new state until the re-rendering happens). Whenever we hit a code that updates a state/prop in React. React updates the temporary state, then takes a snapshot of the existing virtual DOM, then using new state renders a new virtual DOM, then compares these two DOMs using a diffing algorithm called Reconciliation. Once all these done, React takes the new virtual DOM as a reference to efficiently update the actual DOM in browser using a process called Fiber. But this affects the entire render tree in the virtual DOM. It means, a child component which props are not changed, also gets re-rendered just because its parent got rendered again. To avoid this we have three options, but these can turn into extra headache as the codebase grows. Let’s first see how these options has been working and how the new compiler solves it.

React state update process

memo

When we wrap a component with memo then that component won’t re-render on every state change unless there is a change in its prop. But React does NOT guarantee it and says this : memoization is a performance optimisation, not a guarantee.

But if you set a state variable to its current value, React will skip re-rendering your component even without memo. You may still see your component function being called an extra time, but the result will be discarded.

const [nearCount, setNearCount] = useState<number>(0);
<p onClick={() => setNearCount(0)}> // This will re-render again
    {nearCount}
</p>
const [nearCount, setNearCount] = useState<number>(0);
<p onClick={() => setNearCount(1)}> 
    {nearCount}
</p>
// This will re-render twice at max and then stop, no matter
// how many times we click on it

Even when a component is memoized, it will still re-render when a context that it’s using changes. Memoization only has to do with props that are passed to the component from its parent.

useMemo

If we pass a string, boolean, number as prop and they don’t change, then it won’t be re-rendering the consuming component if it is wrapped in React.memo . But when we are passing objects as props, then each time the parent re-renders, that object gets a new reference, which in turn, re-renders the child ignoring the memoized nature. In this case we can use useMemo to memoize the object itself, so that it won’t get a new reference between re-renders.

// From parent component
const [name, setName] = useState('Taylor');
const [age, setAge] = useState(42);
const personProp = useMemo(() => ({age, name}),[age, name])
// the memoization will only break to return a new reference when
// either age or name changes its value

The problem of reference in objects also extends to functions as well. And we can do the same with functions by returning them from an useMemo, but to make it more readable we can use useCallback

useCallback

Same outcome from the both the codes below. But the useCallback one seems more readable and intuitive.

const handleSubmit = useMemo(() => {
    return (orderDetails) => {
      post('/product/' + productId + '/buy', {
        referrer,
        orderDetails
      });
    };
 }, [productId, referrer]);
const handleSubmit = useCallback((orderDetails) => {
    post('/product/' + productId + '/buy', {
      referrer,
      orderDetails
    });
 }, [productId, referrer]);

The new compiler

The key we are chasing here is Super Granularity . With the new compiler, our components are de-structured differently compared to what is the case now. So that every prop and state (a component is consuming) is cached by default and at correct level. Even the functions and object references used as dependencies in useEffect are memoized.

Thanks to Youtuber-Developer Jack Herrington, we have this cool tool to see these inner workings in simple and visual manner. See the screenshot below to see the difference between the older one vs the new one, respectively.

Current react transpiler New react compiler

This compiler is already in use in the web app version of Instagram. Changes like this feels like a real update and make React go the right path, eventually bringing better DX to the developers. After this, if they ship a default way to setup a React app without using a framework, then I might change my go to framework from Astro back to React. So, let’s wait and watch.

Thanks for reading this through 🌙