DEV Community

Paramanantham Harrison
Paramanantham Harrison

Posted on • Originally published at learnwithparam.com

useRef helps you to avoid re-rendering of the component

useRef can store any mutable data that you want to persist between renders. It helps you to avoid re-rendering of the component when you don't want to.

useRef vs useState

useRef is similar to useState but there are some differences,

  • both useState and useRef can maintain the value between renders.
  • useState is used to store the state of a component whereasuseRef is used to store any mutable value.
  • useState will cause the component to re-render when the state is updated whereas useRef will not cause the component to re-render when the value is updated.
const [text, setText] = useState('')
const handleTextChange = (e) => {
  setText(e.target.value)
}

// re-renders the component on every text change
return (
  <div>
    <input type="text" value={text} onChange={handleTextChange} />
  </div>
)
Enter fullscreen mode Exit fullscreen mode

Using useRef to store the value of the input element will not cause the component to re-render when the value is updated.

const textRef = useRef('')
const handleTextChange = (e) => {
  textRef.current = e.target.value
}

// no re-renders when the text changes
return (
  <div>
    <input type="text" value={textRef.current} onChange={handleTextChange} />
  </div>
)
Enter fullscreen mode Exit fullscreen mode

useRef is mostly used for,

  • storing the previous value of a state or props of a component across rendering of a component
  • accessing DOM nodes in React

useRef to store the previous value of a state or props of a component

import React, { useState, useRef } from 'react'

const Slide = ({ selectedSlideIndex }) => {
  const [slide, setSlide] = useState(selectedSlideIndex)
  const prevSlideRef = useRef()

  // update the previous slide value when the slide value changes
  useEffect(() => {
    prevSlideRef.current = slide
  }, [slide])

  const prevSlide = prevSlideRef.current

  return (
    <div>
      <p>Current slide: {slide}</p>
      <p>Previous slide: {prevSlide}</p>
      <button onClick={() => setSlide(slide + 1)}>Next</button>
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

In the above example, useRef helps to maintain the previous value of the slide state variable.

Some of the use cases are,

  • undo/redo functionality
  • maintaining the previous value of a state variable to compare with the current value and perform some action
    • saving a draft if value of a textarea is changed
    • showing a confirmation dialog if the value of a textarea is changed and the user tries to navigate away from the page

useRef to access DOM nodes

import React, { useRef, useEffect } from 'react'

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

  // focus the input element when the component is mounted
  useEffect(() => {
    inputRef.current.focus()
  }, [])

  return (
    <div>
      <input ref={inputRef} type="text" />
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

In the above example, useRef helps to access the input element and focus it when the component is mounted.

Some of the use cases are,

  • focusing or blurring an element
  • accessing the DOM node to get the size of an element
  • accessing the DOM node to get the scroll position of an element

Hope this helps to learn the magic of useRef hook. Happy referencing 😃

Top comments (1)

Collapse
 
merri profile image
Vesa Piittinen

Maybe this is mindblowing to someone:

function Component(props) {
  // can also be: const latest = useRef(props).current;
  const [latest] = useState(props);
  Object.assign(latest, props);

  // stable never changing callbacks that take `latest` as dependency
  const { hello, world } = useMemo(() => {
    function hello() {
      if (latest.active) latest.onClick();
    }

    function world() {
      if (latest.disabled) latest.onLifeHack();
    }

    return { hello, world };
  }, [latest]);

  return <div data-whatever />;
}
Enter fullscreen mode Exit fullscreen mode

The benefit: as latest never changes (it always has the same object reference) you still do get access to the latest props. This pattern can be easier than writing a bunch of useCallback, especially if all of the callbacks can remain stable.

Sometimes it can also be useful that the callback changes when props change, but usually when dealing with things like event handlers you just want the latest prop without mutating the rendered callback that is already in DOM.