The Startup
Published in

The Startup

All About the React useRef Hook with a Real World Example

React hooks were introduced in React v16.8, and made functional components incredibly powerful. With React hooks like useCallback , useEffect , and others (all of which I’ve written about), developers were equipped with the tools to turn React functional components into the building blocks of all React applications.

In this article, we’ll be looking at the React hook useRef and how we can use it to upgrade our React functional components.

Photo by Daniel Leone on Unsplash

What is useRef?

What exactly is the useRef hook?

const refContainer = useRef(initialValue);

useRef takes in a single function argument, initialValue , and returns a mutable reference object whose .current value is initialized to the passed argument. useRef is essentially a “box” whose current key holds a mutable value.

useRef serves a couple main purposes:

  1. Access DOM elements
  2. Persist values across successive renders

Accessing DOM Elements

useRef is most commonly used when accessing React DOM elements. For example, if you’re trying to access an input element after it’s been mounted to the DOM, instead of using the traditional document.getElementById or any other document method to access to element (like you would in vanilla JS), you can use a useRef hook. Lets take a look at an example of this below:

In this code, we are creating a component Form and returning a form element. We invoke useRef with a null function argument, so useRef will return an object { current: null } assigned to inputRef . Since we pass this to the ref parameter of input , we are assigning inputRef to the input DOM element. Now we can access and manipulate input using the inputRef variable, in this case setting focus on the input on initial load using the useEffect hook.

Persist Values Across Successive

useRef isn’t just for DOM refs, but it’s a generic container that can hold anything, similar to an instance property on a class. There are situations where you may want to persist values across renders instead of recreating them on each render. Instead of storing these values in states which may cause additional unnecessary rendering, you can put them in useRef ‘s current property. For example, lets look at this Timer component.

Here, you can see we’re using useRef to keep track of an interval ID that’s persisted across renders, allowing us to create a timer on first load and clear it on last unmount.

There is one thing to keep in mind, useRef doesn’t notify you when it changes Mutating the .current property won’t cause a re-render. If you want to run code when stuff is being mutated, it’s probably better to use a useCallback instead.

Real World Example

When learning about the useRef hook, I initially was a little confused on where I could actually use this in React. However, I’ve found that useRef can be used to create a custom comparison instead of the shallow one that useEffect does by default.

Lets look at this Todo component with a point value that randomly increase.

Our expectation is that the useEffect hook on line 4 will only run when we increase the number of points the todo is worth. However, if we run this code and click the button a couple times, we’ll see that regardless of if the points value changes, the useEffect hook will always run!

This is because useEffect does a shallow comparison by default and todo is an object!

Lets try using the lodash deepEqual operator in our useEffect to see if we can fix this bug:

Now we run into another problem, how do we access previousTodo ? This is where useRef comes to the rescue, we can save previousTodo to the useRef current value to access on each subsequent re-render!

Now we’re keeping track of the previous todo by saving it to the .current property of the useRef hook since it survives after each render. Another useEffect hook is used to update the previousTodoRef.current value after each re-render. Finally, we can now extract the previousTodo value to do a deep compare to ensure that we only log when the todo actually changes!

If we want to go one step further, we can actually extract all this logic to a new hook called usePrevious :

Finally, lets apply this custom usePrevious hook to our Todo component:

That’s pretty sweet, we’ve now created a working Todo component that keeps track of previous values to compare against!

Conclusion

The useRef hook is a powerful hook for two main purposes: accessing DOM elements and persisting values across re-renders. We saw how we can use useRef in both of these cases to write cleaner and better React code! Looking for more resources on the useRef hook? Check out the React documentation for more information!

Keep in Touch

There’s a lot of content out there and I appreciate you reading mine. I’m a undergraduate student at UC Berkeley in the MET program and a young entrepreneur. I write about software development, startups, and failure (something I’m quite adept at). You can signup for my newsletter here or check out what I’m working on at my website.

Feel free to reach out and connect with me on Linkedin or Twitter, I love hearing from people who read my articles :)

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Caelin Sutch

Founder, engineer, designer. Passionate about building cool shit.