🏷 Using refs with useRef hook

In this article you will learn about the useRef hook.

If you are not familiar with refs in general, refs are primarily a way to access the DOM in React.

Think of refs like as a type of tag that you put to a DOM node, in order to be able to track it’s particular content.

✏️ Basic example of how we used refs before hooks:

export default function() {
  //instantiate a new ref
  const myRef = React.createRef()

  const logRef = () => console.log('My ref content:', myRef)

  const addText = () => (myRef.current.innerText = 'Fernando')

  return (
    <>
      <div ref={myRef} />
      <button onClick={logRef}>Log ref!</button>
      <button onClick={addText}>Add value</button>
    </>
  )
}

We are passing a ref object to React when we do <div ref={myRef} /> .

By doing this myRef will automatically have a .current property holding the content of the DOM node. It a property of the node changes, that change will also be reflected in myRef.

If you run the above code and click on Log ref you will get this:

{ current: div }

Now, if you click on Add value you will notice that Fernando will be display and if you click Log ref again and you inspect the object, you will notice that the textContent property now has the value of Fernando.

You can learn more about refs and the DOM in the official react docs.

✍🏻Now let’s refactor with hooks

The only thing that we have to do in order to refactor to use useRef is importing it from React and replacing createRef with useRef.

import React, { useRef } from 'react'

export default function() {
  const myRef = useRef()

  const logRef = () => console.log('My ref content:', myRef)

  const addText = () => (myRef.current.innerText = 'Fernando with useRef')

  return (
    <>
      <div ref={myRef} />
      <button onClick={logRef}>Log ref!</button>
      <button onClick={addText}>Add value</button>
    </>
  )
}

When you instantiate a new ref with useRef, you create a brand new mutable JavaScript object.

Think of useRef as a “container” that can store a mutable value in its .current property.

🗒 Using it in on a simple form

import React, { useRef } from 'react'

export default function() {
  const nameRef = useRef()
  const emailRef = useRef()

  const handleSubmit = e => {
    e.preventDefault()
    const {
      current: { value: name },
    } = nameRef
    const {
      current: { value: email },
    } = emailRef

    const data = { name, email }
    console.table(data)
  }

  return (
    <form onSubmit={handleSubmit}>
      <label>
        Name:
        <input ref={nameRef} />
      </label>
      <label>
        Email:
        <input ref={emailRef} />
      </label>
      <button type="submit">Submit data!</button>
    </form>
  )
}

In this example we leverage both name and email refs, to get their .current.value in order to access the information that a user typed.

Something to remember: Mutating the .current property from useRef it’s not a change neither of the state or props, so this won’t cause a re-render.

📥 Passing refs from parent to child

The previous example of a basic form will work but, what if you want to pass refs from parent to child 🤔. This approach won’t work.

Enter forwardRef

In order to pass or forward a ref from a parent to one of its children you need to use forewarRef.

React docs note: This is typically not necessary for most components in the application. However, it can be useful for some kinds of components, especially in reusable component libraries.

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

//Create a child component usign forewardRef
const StyledInput = forwardRef((props, ref) => (
  <input type="text" className="styled-input" ref={ref} />
))

export default function() {
  const nameRef = useRef()
  const emailRef = useRef()

  const handleSubmit = e => {
    e.preventDefault()
    const {
      current: { value: name },
    } = nameRef
    const {
      current: { value: email },
    } = emailRef

    const data = { name, email }
    console.table(data)
  }

  return (
    <form onSubmit={handleSubmit}>
      <label>
        Name test!:
        <StyledInput ref={nameRef} />
      </label>
      <label>
        Email:
        <StyledInput ref={emailRef} />
      </label>
      <button type="submit">Submit data!</button>
    </form>
  )
}

React’s forewardRef accepts a callback that takes to arguments: props and ref.

This feature of react allows a component to take a ref they receive, and pass it down to a child.

Hope you enjoyed reading, Happy hacking! 👻

Read more about hooks:


fermaddev
Written by@fermaddev
I build stuff with computers and on my spare time I'm a Software Engineer.

GitHubTwitter