Difference Between useState and useRef in React

This article is originally published at WebDevIdea.

React is an extremely popular JavaScript library for building user interfaces. A lot of developers prefer this library because it’s all based on components and has a lot of cool packages that we can use. In addition to that, now we have React hooks which came to save us from the complexity of class components.

React Hooks are very powerful and allow us to use state in functional components. They also give us the ability to create logic and functionality inside stateless functional components. Many developers now prefer to use hooks and functional components rather than class components because the class syntax is a little hard to write. There are a lot of useful hooks that you can use in your React code to create logic and add features to your components.

That’s why in this article, we will learn about both the hooks useState and useRef by covering the differences between them. So let’s get started

The useState hook

The hook useState is just a function that accepts one argument(initial state) and returns two things:

The current state(the value of our state).
A function that allows us to update that current state.
The hook useState allows us to have state in functional components and we can use it to create a lot of cool things in React. With useState, we can for example change the text after clicking a button, or create a counter, and so on. There is a lot you can do with this important hook in React.

So if you want to start using useState in React, you will have to import it first from the react package.

Here is an example:

import React, { useState } from 'react'

Now after importing it from the react package, you can use the hook inside functional components without any problems.

Examples

In the example below, we will use the hook useState to create text and update it after clicking a button:

//import useState.
import React, { useState } from 'react'

function MyComponent() {
    // Using useState.
  const [name, setName] = useState('Mehdi')

  //JSX.
  return(
      <>
      <h1>{name}</h1>
      <button onClick={()=> setName("John")}>Change Name</button>
      </>
  )
}

export default MyComponent;

As you can see above, the hook useState allowed us to update the state after clicking the button. We passed a string name as an argument for the hook function, you can pass it anything such as an array, number, boolean, all that depends on what type of state you’re dealing with.

Also, notice that we used ES6 array destructuring to specify the initial state and the updater function. The value name refers to the initial state "Mehdi" and the value setName refers to the function that will allow up to update the state. We also called the updater function setName in the click event in order to update the name state from "Mehdi" to "John". As a result, the value name inside the heading h1 gets updated after clicking the button.

So the hook useState is very useful as it allows us to use state and update it inside functional components without having to use class syntax.

Here is another example of a counter that allows us to increment the number by 1 after clicking a button:

//import useState.
import React, { useState } from 'react'

function MyComponent() {
    // Using useState.
  const [counter, setCounter] = useState(0)

  //JSX.
  return(
      <>
      <h1>{counter}</h1>
      <button onClick={()=> setCounter(counter + 1)}>Increment</button>
      </>
  )
}

export default MyComponent;

In this example, we set the initial state to 0 number as a parameter for the hook function. That’s because we are dealing with numbers and we need to increment the number by 1 each time we click the button. The updater function setCounter allows us to update the state to the current state plus 1. As a result, we can increment the counter by 1 after each click.

You can also check out a live demo on Stackblitz if you want.

The useRef hook

The hook useRef is a bit similar to useState , it returns an object that has a property current inside which we can access using object dot notation. That property current takes the value of the argument that we pass to the function useRef().

So the hook useRef also accepts one argument(the initial value for the property current). Also, keep in mind that the returned object will persist for the full lifetime of the component.

Again, to start using the hook, you have to import it from React first. Then you can use it without any problems.

import React, { useRef } from 'react';

Let’s try the hook in the console to see how it works:

//using useRef and giving it 0 as a parameter.
const ourRef = useRef(0);

console.log(ourRef);
  //{ current: 0 }
console.log(ourRef.current); // 0

As you can see, useRef returns an object containing a property that has the value of the parameter we passed. We can access that value using object dot notation.

useRef is powerful because it’s persisted between renders. Unlike useState, useRef doesn’t cause a component to re-render when the value or state changes.

To make things more clear, let’s look at a practical example. We will show you the same example of the incrementing counter that we did above with useState, but now using useRef.

Here is the example:

//import useRef.
import React, { useRef } from 'react'

function MyComponent() {
    // Using useRef.
  const ourRef = useRef(0)

  //JSX.
  return(
      <>
      <h1>{ourRef.current}</h1>
      <button onClick={()=> ourRef.current = ourRef.current + 1}>Increment</button>
      </>
  )
}

export default MyComponent;

As you can see, we set the initial value to 0 and we accessed the property current in the returned object to increment our counter by 1. Now the problem is that the number 0 doesn’t increment even though if we click the button. That’s because the hook useRef doesn’t cause the component to re-render. The component needs to render in order to update the UI.

If you printed the value of the current property in the console, you will realize that when you click the button the value actually increments by 1. But it doesn’t show up in the UI because the component doesn’t get re-rendered. So useRef is not a good option for creating a counter. You can check out a live demo on Stackblitz if you want.

UseRef usecases

One of the main use cases of using the hook useRef is to reference DOM elements in React. Every element in the DOM has an attribute called ref which we can set our ref to. Here is an example that allows us to access an input element and focus on it after clicking a button:

const Mycomponent = ()=> {
  const inputRef = useRef(null)

  const inputFocus = () => {
    inputRef.current.focus()
  }

  return (
    <>
      <input ref={inputRef} />
      <button onClick={inputFocus}>Focus on the Input</button>
    </>
  )
}

Another use case of useRef is for the storage that is persisted across component renders. The hook useRef allows us to store the previous value of a state. You can learn more about that if you’re interested.

useState VS useRef

For useState:

  • Allows functional components to have their own state.
  • Allows us to update the state inside components.
  • It causes components to re-render after state updates.
  • Returns the current state.
  • Has an updater function that updates the state.

For useRef:

  • Returns an object with a property containing the initial value.
  • Doesn’t cause a component to re-render when the value or state changes.
  • Data is persisted between renders.
  • Allows to reference DOM elements.

So these are the differences between these two extremely useful React hooks.

Conclusion

As you can see, both the hooks useState and useRef are a bit similar. The difference is that useState returns the current state and has an updater function that updates the state. While useRef returns an object, doesn’t cause components to re-render, and it’s used to reference DOM elements.

Thank you for reading this article.

30