The difference between  useState()  and useRef()

The difference between useState() and useRef()

React js is an open-source javascript library that was developed by Facebook. It specializes in building interactive user interfaces in lesser lines of code. One of the most important features of react js is a Component. The component is an independent and reusable code that returns the JSX code. It enables us to think about a certain problem independently.

There are two ways of creating a component

  1. Function Component

  2. Class based Component

In this article, we are going to talk about two hooks ( useState() & useRef() ) and their differences that are used in the functional component.

What is useState()?

It is a hook that lets us add the "react" state into the function Component. A state is a javascript object that stores information or data and whenever that data changes it re-renders the component in which it is declared and also re-renders all its child components with the updated state value on the screen.

Syntax: -

const [stateName, setStateName] = useState('initalValueOfState');

The above line of code is only executed once when the component mounts into the DOM and it is ignored whenever the component re-renders.

Parameters

  • initialState - It is the value that is assigned to the state whenever the component mounts into the DOM. Any value can be passed inside the useState(), it can be a variable, String, Number, Object, and function.

Returns

  • stateName : - It is the name of the state that is assigned with the initial value passed inside the useState() brackets whenever the component mounts into the DOM.

  • setStateName - It is a function that is being used to update the state. We can use any name for the function but it is the best practice to use "set" as a prefix for the state function.

    IMPORTANT NOTE: - Hooks can only be declared inside the functional component, not in any other kind of function.

    Why do we use useState()?

    First of all, we will look at an example through which we will come to know what kind of problems we face when we don't use useState().

    Let's get started!!

      import React from 'react'
    
      function Counter() {
        // created a variable
        let count = 0
        const counterHandler = () => {
          count++
          console.log("the value of count" + count);
        }
        return (
          <div>
            <button onClick={counterHandler}>Increase Counter</button>
            <div>{count}</div>
          </div>
        )
      }
    
      export default Counter
    

    In the above⬆️ lines of code what we are doing, is creating a button🔼 that will increase📈 the count by 1 whenever we click on that button.

    Well, everything seems fine because whenever we click on that button it updates

    the count by 1 and we can also see that in the console.

    The problem does not lie there, It lies on the screen because whenever we are clicking on that button it increases that count by 1 but does not update that count value on the screen.

    It is because when the component first mounted into the DOM and it returned that JSX or HTML code to the browser and afterward even if we update the count value, it will not be updated on the screen as the component is not re-rendered again.

    Re-render means the code inside the component needs to be revaluated so that if any changes happen in the component, it can be updated on the screen.

    All the code from the top of the component to the end of the component will be re-evaluated with the updated value of the state.

That is why useState() comes into the picture because it tracks changes of the state and updates the DOM whenever changes happen to the state.

Now let's learn how to use useState()

How to use useState()?

I have already discussed how to declare usestate() and now I wanted to show that there are two ways of creating a useState().

const [counter, setCounter] = useState(0);
const [secondCounter, setSecondCounter] = useState(() => {
    return 0;
  });

The first one we have already discussed above. So in the second declaration, we are using a function as a parameter that returns some value that gets stored inside the state variable.

Both of them are the same but the difference lies in the performance, as the first declaration is slow because every single time when the component re-renders, it revaluates the stored value inside useState() even though it does not get stored inside the state variable.

So it is better to use the arrow function as a parameter for the complex and slow computation for the initial state.

But In the second declaration, the arrow function only runs a single time when the component mounts into the DOM.

Now, we will learn how to update the state

Updating the state

There are mainly two ways of updating the state

  • Passing the value inside the function.

  • Passing the arrow function that returns the value.

    First, look at how to pass the value inside the function and update the state

function StateChanger() {
  const [count, setCount] = useState(0)

  const decreaseCountHandler = () => {
    setCount(count - 1)
  }

  return (
    <div className={classes.container}>
      <button onClick={decreaseCountHandler}>-</button>
      <span>{count}</span>
    </div>
  )
}

We pass the value inside the "setCount" function to update the count state which will cause the component to re-render and update the count everywhere, and this way we will get the updated value on the screen.

function StateChanger() {
  const [count, setCount] = useState(0)

  const decreaseCountHandler = () => {
    setCount(count - 1)
  }
  const increaseCountHandler = () => {
    setCount((count) => {
      return count + 1
    })
  }

  return (
    <div className={classes.container}>
      <button onClick={decreaseCountHandler}>-</button>
      <span>{count}</span>
      <button onClick={increaseCountHandler}>+</button>
    </div>
  )
}

export default StateChanger

This time⏲️ I have added another method called as "increaseCountHandler", which also contain "setCount" method but I didn't pass the value directly inside the method (setCount()) as an argument, I have passed an arrow function that will get a parameter as count state (count), this is the better way of updating the state if current state depends on the previous state.

what is useRef()?

useRef() is a hook that is used to persist value between the renders. It returns a reference to the object that contains a property name as "current". As you can see below the declaration of useRef() hook and how to update the current property in the ref object.

Syntax:-

const ref = useRef(0);
// storing 0 in ref.current

Updating the value

It is quite simple to update the value. It is like updating the property in the object.

ref.current = ref.current + 1;
// OR
ref.current = 0;

How to use useRef()?

It is quite simple to use useRef(). Firstly we declare the useRef() and store some initial value inside the useRef as a parameter. We can change the value of the "current" property at any time.

Let's see how to use useRef() with an example down below 👇

import './App.css'
import { useRef } from 'react'
function App() {
// declartion of useRef hook 
  const ref = useRef(0);
  const onClickHandler = () => {
    // updating ref.current value
    ref.current = ref.current + 1;
    console.log(ref.current)
  }
  return (
    <div className="App">
      <button onClick={onClickHandler}>Click me</button>
      <p>{ref.current}</p>
    </div>
  )
}

export default App

So In the above code whenever we click on the "click me" button it triggers the "onClickHandler" method which is used to update the value of ref.current .Whenever the useRef.current value changes it does not cause the component to re-render. As updating the value of ref.current does not cause the component to re-render, the value of ref.current on the screen will not be updated.

Then one question should come into your mind that is why do we not use a variable rather than using useRef()? 🤔

I will answer this in "why do we use useRef()"

Why do we use useRef()?

  • It persists value between the renders.

  • It does not cause the component to re-render.

  • It is used to reference the DOM element.

Now let's see👀 what will happen if we use variable rather than useRef()

function App() {
  var value = 0;
  const onClickHandler = () => {
    value++
    console.log(value)
  }
  return (
    <div className="App">
      <button onClick={onClickHandler}>Click me</button>
      <p>{value}</p>
    </div>
  )
}

export default App

In The above code, everything is the same, I have exchanged useRef() declaration with the variable initialization and updation of the useRef() with the variable updation. It will still give the same result as the useRef() but the only difference is that whenever the component will re-render, the "value" variable will again be initialized with 0 and that is something we don't want.

Then we should keep the variable outside the component then the variable will not get initialized whenever the component re-renders.

I am doing the same thing that you have suggested.

var value = 1
function UpdateValue() {
  const onClickHandler = () => {
    value++
    console.log(value)
  }
  return (
    <div className="App">
      <button onClick={onClickHandler}>Click me</button>
      <p>{value}</p>
    </div>
  )
}

export default UpdateValue

There is still some problem in that that is if you will reuse this component multiple times, even though the button will be different but they will be updating the same variable which is "value". You can see that below 👇

import './App.css'
import { useRef } from 'react'
import UpdateValue from './Components/UpdateValue'

function App() {
  return (
    <>
      <UpdateValue></UpdateValue>
      <UpdateValue></UpdateValue>
      <UpdateValue></UpdateValue>
    </>
  )
}

export default App

Those are the two reasons that is why we don't use variables rather than using useRef().

What is the difference between useState() and useRef()?

useState()

  • it is used to create a state inside the functional component.

  • React always tracks the change in state variable if it changes, components get re-render along with its child component.

  • updation of the state is asynchronous in nature, as you can see below👇

import React from 'react'
import { useState } from 'react'
function StateComponent() {
  const [state, setState] = useState('InitialState')
  const onClickHandler = () => {
    setState('updatedState')
    console.log(state)
  }
  return <button onClick={onClickHandler}>Click me</button>
}

export default StateComponent

Explanation:-

Even though I am consoling the state after updating the useState(), I am still getting "InitialState" as output, It is because the updation of the state is asynchronous in nature because of that first of all the synchronous code will be executed then the state will be updated that is why I am getting "InitialState" as output.

useRef()

  • It persists value between the renders.

  • It does not cause the component to re-render.

  • updation of the "current" property in the object is synchronous in nature, unlike the updation of the state.

  •     import React from 'react'
        import { useRef } from 'react'
        function StateComponent() {
          const ref = useRef('InitialState')
          const onClickHandler = () => {
            ref.current = 'updatedState'
            console.log(ref.current)
          }
          return <button onClick={onClickHandler}>Click me</button>
        }
    
        export default StateComponent
    

Explanation:-

As you can see, this time the value gets updated first then it gets printed. It is because the updation of the "current" property is synchronous in nature.

Conclusion

This article addresses the useState() and useRef() hooks and their differences. It should be clear till this point that there is nothing like a good and bad hook. Both of them have different use cases and applications. I have covered all the important points along with examples of useState() and useRef().

That's all from my side! Hope you enjoyed reading it and learned something. Thank you for reading, do share your thoughts about useState() and useRef() and what you like or dislike about it in the comment section. You can follow me on Twitter at Susaksham Jain and subscribe to my newsletter to get the latest articles from me in your inbox📩.