Demystifying useRef: A React Hook Guide
Published: 2024-04-29 19:56:32

---
canonical_url: https://antondevtips.com/blog/demystifying-useref-a-react-hook-guide
---

## Introduction

**useRef** is a versatile hook in React that allows handling DOM references and storing data across component re-renders without triggering a re-render itself.
Unlike state variables managed by `useState` or `useReducer`, changes to a ref don't cause the component to update and re-render.
This makes `useRef` perfect for certain tasks, such as accessing DOM elements directly, storing previous state, managing timers, keeping track of mutable data and accessing current value in the non React callbacks.


## Understanding useRef React Hook

`useRef` hook can be declared in the following way:

```jsx
const ref = useRef(initialValue);
```

This hook returns a mutable ref object that will persist for the full lifetime of the component.
This object has a property called `.current` that can be used to access or set a value of the ref object.
`useRef` like the `useState` hook has a single `initialValue` parameter that sets an initial value to the `.current` property.


## When to USe useRef React Hook

### Accessing DOM Elements

One of the most common uses of `useRef` is to directly interact with a DOM element.
This approach is handy for focusing an input element or accessing its data.

```jsx
export const InputWithFocusButton = () => {
    const inputRef = useRef(null);

    const onButtonClick = () => {
        inputRef.current.focus();
    };

    return (
        <>
            <input ref={inputRef} type="text" />
            <button onClick={onButtonClick}>Focus the input</button>
        </>
    );
}
```

In this component when you click "Focus the input" button - a text input is manually receiving a focus.
This is possible by using a reference to the input HTML element.

First, an empty ref is defined `const inputRef = useRef(null);` and then assigned with an HTML element:

```jsx
<input ref={inputRef} type="text" />
```

After that you can use `inputRef.current` to access the input properties and functions. Finally, `inputRef.current.focus();` sets the focus to the input element.


### Storing Previous State

`useRef` hook can be used to keep track of previous states or props without causing re-renders:

```jsx
export const CoffeeCounter = () => {
    const [count, setCount] = useState(0);
    const prevCountRef = useRef();

    useEffect(() => {
        prevCountRef.current = count;
    }, [count]);

    return (
        <div>
            <h1>Now: {count}, before: {prevCountRef.current}</h1>
            <button onClick={() => setCount(count + 1)}>
                + 1 coffee
            </button>
            <button onClick={() => setCount(count - 1)}>
                - 1 coffee
            </button>
        </div>
    );  
};
```

In this example a 2 coffee counters are displayed on the screen: the most recent value and a previous one.
When the `count` state is updated - the `prevCountRef` saves its value.
When `count` value is updated - it causes a re-render and its value is immediately displayed on the screen.
However, as `prevCountRef` doesn't cause a re-render - its previous value is displayed.

![Screenshot_1](/media/code_screenshots/react/use-ref/img-react-useref_1.png)


### Holding Mutable Data

You can use `useRef` hook to hold mutable data that you want to persist across re-renders but don't want to cause re-renders when this data changes.

```jsx
export const Timer = () => {
    const intervalRef = useRef();

    const startTimer = () => {
        intervalRef.current = setInterval(() => {
            console.log("Timer tick");
        }, 1000);
    };

    const stopTimer = () => {
        clearInterval(intervalRef.current);
    };

    return (
        <>
            <button onClick={startTimer}>Start Timer</button>
            <button onClick={stopTimer}>Stop Timer</button>
        </>
    );
}
```

In this example a `useRef` is used to store a reference to an `intervalId` returned by `setInterval` function.
Using a ref in this case is safer and more efficient way to start and stop the interval without causing redundant renders.


## Tips and Tricks When Using useRef React Hook

### Avoid Recreation of Ref objects

React stores the initial value in the `useRef(initialValue)` only once and ignores this initial value on the next renders.

Let's have a look on example where we might use a complex data structure or a third-party library that involves an expensive setup process:

```jsx
import ComplexLibrary from 'some-complex-library';

export const ExpensiveComponent = () => {
    const complexRef = useRef(new ComplexLibrary());
    
    return (
        <div>
            <button onClick={() => complexRef.current.doSomething()}>
                Do Something
            </button>
        </div>
    );
}
```

While a value returned by creating `ComplexLibrary` is used only during an initial render and is ignored on the following ones - the initialization of `ComplexLibrary` is still called on every render.
It might be very inefficient and slow down the entire application. It is recommended to use the following pattern to make this code more efficient:

```jsx
import ComplexLibrary from 'some-complex-library';

export const ExpensiveComponent = () => {
    const complexRef = useRef(null);

    if (complexRef.current === null) {
        complexRef.current = new ComplexLibrary();
    }
    
    return (
        <div>
            <button onClick={() => complexRef.current.doSomething()}>
                Do Something
            </button>
        </div>
    );
}
```

Here we make sure that `complexRef` is initialized with a value only when it is null.
And when it is already initialized - the complex initialization is not executed at all.

### Avoid Null Checks When Initializing useRef Later

When using a type checker you will receive null reference warning if you initialize `useRef` with a real value later.
For example, you will get such a warning in the previous example, because a complexRef has `null` as initial value.

![Screenshot_1](/media/code_screenshots/react/use-ref/img-react-useref_2.png)

To get rid of this null warning, you can use the following pattern:

```jsx
const complexRef = useRef(null);
    
const getComplexRef = () => {
    if (complexRef.current !== null) {
        return complexRef.current;
    }

    const complexObject = new ComplexLibrary();
    complexRef.current = complexObject;
    
    return complexObject;
}
```

Then you can call `getComplexRef()` to access a `complexRef.current` without null access warnings:

```jsx
export const ExpensiveComponent = () => {
    // ...
    
    return (
        <div>
            <button onClick={() => getComplexRef().doSomething()}>
                Do Something
            </button>
        </div>
    );
}
```

### How To Pass Reference to Child Components

By default, own components don't expose refs to the DOM nodes inside them.
You aren't able to do something like this:

```jsx
export const CustomInput = ({ value, onChange }) => {
    return (
        <input
            value={value}
            onChange={onChange}
        />
    );
}

export const ForwardRefExample = () => {
    const inputRef = useRef(null);

    return <CustomInput ref={inputRef} />;
}
```

Instead, you should wrap the `CustomInput` component with a `forwardRef` function:

```jsx
export const CustomInput = forwardRef(({ value, onChange }, ref) => {
    return (
        <input
            value={value}
            onChange={onChange}
            ref={ref}
        />
    );
});

export const ForwardRefExample = () => {
    const inputRef = useRef(null);

    return <CustomInput ref={inputRef} />;
}
```

Now a **ref** can be safely retrieved from the `CustomInput` component: `<CustomInput ref={inputRef} />`.


## Caveats and Pitfalls When Using useRef React Hook

Take into account the following nuances when using a `useRef` Hook:

* When you update the `ref.current` property, React does not re-render the component.
* Do not read or write `ref.current` during rendering, except for initialization. This can make your component's behavior unpredictable.
* You can mutate the `ref.current` property. However, if it holds an object that is used for rendering, then you should avoid value mutation.
* When using Strict Mode in development, React will call your component function twice in order to help you find accidental impurities.
Each ref object will be created twice, but one of the versions will be discarded. If your component function is pure (as it should be), this should not affect the behavior.
This behaviour does NOT affect production.


## Summary

`useRef` is a powerful hook in the React ecosystem, providing an elegant solution for accessing DOM elements and storing mutable data across renders without additional rendering.
By understanding and applying `useRef` in your React applications, you can achieve more control over your components and optimize your application's performance.

Remember to use `useRef` wisely, as typically most of the use cases can be solved without using it.
When using `useRef` too much - you can make the code less readable and less predictable.

Consider the following `useRef` tips: 

* **Not Just for DOM:** While accessing DOM elements is a common use, `useRef` is also valuable for keeping any mutable value around for the lifetime of the component.
* **Avoid Overuse:** Use `useRef` wisely. For instance, if you find yourself synchronizing ref values with state, consider whether state alone could serve your purpose.
* **Combine with useEffect:** `useRef` can be combined with `useEffect` hook to track changes in state or props over time without triggering additional renders.

Hope you find this blog post useful. Happy coding!

_Originally published at_ [_https://antondevtips.com_](https://antondevtips.com/blog/demystifying-useref-a-react-hook-guide)_._

### After reading the post consider the following:

- [Subscribe](https://antondevtips.com/blog/demystifying-useref-a-react-hook-guide#subscribe) **to receive newsletters with the latest blog posts**
- [Download](https://github.com/AntonMartyniuk-DevTips/dev-tips-code/tree/main/frontend/react/use-ref) **the source code for this post from my** [github](https://github.com/AntonMartyniuk-DevTips/dev-tips-code/tree/main/frontend/react/use-ref) (available for my sponsors on BuyMeACoffee and Patreon)

If you like my content —  **consider supporting me**

Unlock exclusive access to the source code from the blog posts by joining my **Patreon** and **Buy Me A Coffee** communities!

[![](https://cdn-images-1.medium.com/max/233/1*GSZFx05RDUWr5pn_E9bK8w.png)](https://www.buymeacoffee.com/antonmartyniuk)

[![](https://cdn-images-1.medium.com/max/229/1*8tJk9eYCJrkzoAJw2cILSA.png)](https://www.patreon.com/bePatron?u=73769486)