Alex Sidorenko

A Visual Guide to React Rendering - Refs

November 16, 2021

How to disable this button after 3 clicks without re-rendering the component first 2 times?

<button disabled={count === 3}>Button</button>

Storing values with refs

When you want a component to “remember” some information, but you don’t want that information to trigger new renders, you can use a ref—it’s like a secret “pocket” for storing information in your component!

React Docs - Referencing Values with Refs

Let’s try to count clicks with refs instead of state.

<button disabled={count.current === 3}>Button</button>

The ref updates, but the button is still active. Why is that?

Component renders and DOM updates

To disable the button react has to update the DOM. React updates the DOM when the component renders with a different output than before. React won’t update any DOM until one of the React components render. And since changing ref doesn’t cause the component to re-render, the button stays active.

To demonstrate this point further, let’s add a parent component.

By default when you render a React component it recursively re-renders all its children. That’s why when we update the Parent state, it renders both Parent and Component. And when Component renders, React executes the condition and disables a button.

<button disabled={count.current === 3}>Button</button>

But surely we can not rely on parent updates to disable a button. Let’s implement this behavior directly into Component.

Update state to re-render a component

We can make the component re-render by reintroducing state again. But we still don’t want the component to render on first 2 clicks. So we will keep the ref to silently count the clicks. And we will add a state variable with a sole responsibility of updating the button status. Let’s update butttonStatus only when the button clicked the third time.

<button
  disabled={buttonStatus === 'disabled'}
  onClick={() => {
    count.current++
    if (count.current === 3) {
      setButtonStatus('disabled')
    }
  }}
>

The example from the article has been made to demonstrate the behavior of refs. Keep in mind that unnecessary renders are not always bad, and you don’t have to eliminate every one of them. In fact, in a real-world scenario, it would probably make more sense to rely solely on the state and re-render this component 3 times for simplicity. However, you will encounter different situations in your apps. Understanding refs gives you a powerful tool for fine-tuning the behavior of your components.