Sitemap

The Ugliest Pattern In React

3 min readJan 7, 2023

--

Brace yourselves. Out of all the nastiness in the React world, nothing comes close to this.

Usually, you will update state in event handlers. However, in rare cases, you might want to adjust state in response to rendering — for example, you might want to change a state variable when a prop changes.

Granted. In most cases, you don’t need this:

  • If the value you need can be computed entirely from the current props or other state, then you can remove the redundant state altogether.
  • If you want to reset the entire component tree’s state, pass a different key to your component.
  • If you can, update all the relevant state in event handlers.

But let’s say that none of those conditions apply, and you still need to update a state when a prop changes.

To solve this problem, seasoned React devs know what to do: Update the state in an Effect.

Nope! The new docs explicitly tell you that an Effect is no good for this because it will cause the child tree to render twice. And sure, you want to avoid extra renders, but at what price?

The new docs recommend instead what I can only call The Ugliest Pattern In React™️. If you are brave to see it for yourself, here it is:

function CountLabel({ count }) {
const [prevCount, setPrevCount] = useState(count);
const [trend, setTrend] = useState(null);
if (prevCount !== count) {
setPrevCount(count);
setTrend(count > prevCount ? 'increasing' : 'decreasing');
}
return (
<>
<h1>{count}</h1>
{trend && <p>The count is {trend}</p>}
</>
);
}

The horror! Yes, it sets state in the render function! It breaks what’s arguably the most important rule of React: The render function must be pure.

I’ll let the docs excuse themselves and give you the full gory details:

You can only update the state of the currently rendering component like this. Calling the set function of another component during rendering is an error. This special case doesn’t mean you can break other rules of pure functions. […]

This pattern can be hard to understand and is usually best avoided. […]

The rest of your component function will still execute (and the result will be thrown away), but if your condition is below all the calls to Hooks, you may add an early return; inside it to restart rendering earlier.

Book of Reactions, 23:20

Yes, they even drive the point home by making me imagine an early return inside of an if-statement that sets state *shudders* in the render function.

And I’m not the only one to find it ugly. Check this recent Hacker News post. All in all, I might go against the new docs and use an Effect for this just because it’s way more readable.

The only consolation I can offer is that nothing else in React is uglier than this.

To be fair, this pattern has been around since hooks first released. But it will likely be encouraged a bit more from now on, given the React team’s renewed interest in reducing unwanted uses of Effects.

Maybe the ugliness is a virtue, since it encourages us to completely change the code to enable some of the better alternatives mentioned above — After all, “adjusting state in response to rendering” will always result in code that’s difficult to understand.

The remaining question is, will god forgive us for the times we have to use this pattern? Only time will tell.

Maybe one day, through repetition, we’ll get used to this pattern and find it beautiful.

For my full breakdown of the new React docs, click here:

Thanks for reading! If you enjoy humorous tech stories like these and want to support me to keep writing forever, consider signing up to become a Medium member. It’s $5 a month, giving you unlimited access to stories on Medium. If you sign up using my link, I’ll earn a small commission. You can also follow me on Medium and Twitter.

--

--

Sebastian Carlos
Sebastian Carlos

Written by Sebastian Carlos

Middle-end developer. Programming, satire, and things. You can buy me a coffee at https://ko-fi.com/sebastiancarlos

Responses (6)