useRef Hook: Secret Recipe of DOM Manipulation - part 18

Learn how to use useRef hook in react with example | elpeeda.net


 In the process of building a React application, you'll encounter a situation where you have the argue to touch the DOM element. For example, to implement a scroll to top button, to focus the input field, set the tooltip position, get element height and width, and so on, there could be many reasons and React provides one solution which is refs.

React works with a single React root Dom element, but it also opens the gate for escape hatches, so you can not only store information of Dom nodes but also manipulate it or work with browser API. You can also use refs for remembering information like the number of times a user tried to log in and you don't want to render this information.

This article is going to take as follows: 

  • How useRef works?
  • The useRef hook simple examples
  • Difference between useRef and useState
  • The useRef tips and best practices

What is useRef hook in React?

The useRef is a hook in React and is used for two main reasons.

  1. Access the DOM element that allows interaction with React components or HTML node elements directly.
  2. Store state or instance values, allow you to persist value across render.
We will learn both cases in detail with example code.

Creating a reference with useRef Hook

Refs is a short form of reference. To get real information about a DOM element we need to create a reference with the help of useRef hook.

Let's declare refs inside the functional component by importing useRef from react library.

import {useRef} from 'react'

useRef initial value null

We will add refs to the component and pass the initial value as an argument to useRef hook, in other words, the initial value can also refer as a placeholder. You can specify any data type as initial, like a number, string, boolean, object, or null.

It's not mandatory but it's a common practice in programming to use null or undefined as initial value. As the user should not interact with the DOM property during render, it'll lead to a behavior difficulty of component prediction; React predicts the outcome of a component based on its props and state.

Initializing the value null, undefined, or zero during render is best practice. 

const buttonRef = useRef(null)

Ref attribute in React 

The ref attribute is a built-in key prop. We can use the ref attribute on any HTML element in which we want the reference value of the DOM node to directly manipulate it or accept the state or props of a component.

Here, is an example of attaching the refs to a button using the ref attribute and storing the reference in the buttonRef constant.

<button type='button' ref={buttonRef} />

Current property and its use cases

The useRef hook returns the ref object with the special current property which holds the current reference values of the element. It's used to access the DOM elements or store instance values which help to maintain React applications.

You can use this current property to read the reference value with reference.current, and modify the current value with reference.current = updateValuewithout causing the component to re-render.

The current property also helps to call method ex-focus or browser API on the element and store the value of timer or event listener and update it as needed.

A simple example that demonstrates current property use to access the DOM element and call method on it.

import { useRef } from "react"
const Form = () => {
  const inputRef = useRef(null)
  const buttonRef = useRef(null)
  
  const handleInputChange = () => {
    buttonRef.current.disabled = inputRef.current.value === ''
  }
  
  return (
   <form>
      <input type='text' ref={inputRef} onChange={handleInputChange} />
      <button ref={buttonRef} disabled>Submit</button>
    </form> 
 )
}
export default Form

Here, we are referencing the input and button, it returns a mutable object with current props which we can read the value and modify by calling the disabled property on the button element.

Modify DOM node elements

In certain situations, we need to access the DOM element in React component and change the behavior of the HTML element which can't be done through state and props alone. For example, implementing custom form validation logic, modifying the properties or styles based on conditions, integrating with third-party libraries, or for some visual effects like animations.

Let's implement the scroll-to-top button that will demonstrate the usage of useRef hook for manipulating the DOM.

Creating a scroll-to-top Button with the useRef hook in React

I'll use scrollRef to store a reference to the scroll container and useState hook to store a boolean value to check the condition of whether the button should appear or not based on scroll position.

import { useState, useRef } from "react"
const ScrollToTop = () => {
  const scrollRef = useRef(null)
  const [disaplayButton, setDisplayButton] = useState(false)
  
  const handleScrollButton = () => {
    if (scrollRef.current.scrollTop > 100) {
      console.log('scrolled')
      setDisplayButton(true)
    } else {
      setDisplayButton(false)
    }
  }
  const handleScrollToTop = () => {
    if(scrollRef.current) {
      scrollRef.current.scrollTo({top:0, behavior:"smooth"})
    }
  }
  return (
    <div ref={scrollRef} style={{position: 'relative', height: '400px', overflow: 'scroll'}} onScroll={handleScrollButton}>
      <p>
      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas sagittis lorem nec massa consequat, vel mattis
orci ullamcorper. Donec lacinia sapien id dolor consectetur, quis lobortis ex finibus. Integer ut ex et velit
      </p>
      { displayButton && 
        <button className="top-button" type="button" onClick={handleScrollToTop}>Top</button>
    </div>
  )
}
export default ScrollToTop

The handleScrollButton function checks the scroll position is greater than 100px and updates the function, the button will only show when the user has scrolled down past the value.

When the button is clicked, the handleScrollToTop function is triggered to scroll to the top position.

The onScroll event handles scrolling events on an element and is used to trigger the handleScroll function.

Make sure to specify the overflow property on the parent div element, set to scroll.

CSS file to style the scroll-to-top button and import this file into the ScrollToTop component at the top.

ScrollToTop.css
.top-button {
  position: fixed;
  bottom: 20px;
  right: 20px;
  background-color: #000;
  color: #fff;
  width: 50px;
  height: 50px;
  border-radius: 50%;
}
.top-button::before {
  content: '';
  position: absolute;
  border-right: 8px solid transparent;
  border-left: 8px solid transparent;
  border-bottom: 8px solid #fff;
  margin: -8px;
}

Usage useRef Hook for Persistent Data storage in React Components

The useRef Hook also stores referencing values that persist across re-renders. It stores values in memory and only updates when you modify it with the current property, which means data remain unchanged even after a component update or re-render due to some action.

Updating the reference values doesn't cause the component to update.

The useRef hook is useful when you want to store input value or scroll position in a constant that persists between renders and only changes when the reference values change.

Keeping track of the Previous value 

We can use referencing value technique to create a functionality that requires a history of previous values.

In this example we'll use the useRef hook to reference the previous value of the counter increases by 5, and we'll alert a message.

 import { useRef, useState } from "react"

 const Counter = () => {
   const [counter, setCounter] = useState(0)
   const prevCounterRef = useRef(0)

   const handleClick = () => {
     setCounter(counter + 1)
   }
   if (counter !== prevCounterRef.current && counter % 5 === 0) {
     alert('Counter increased by 5')
     prevCounterRef.current = counter
   }
   return (
     <>
       <h2>{counter}</h2>
       <button onClick={handleClick}>Increment</button>
     </>
   )
 }
 export default Counter

We reference the counter's previous value and compare it to the current value to generate an alert message if the current count is not equal to the previous value and is divisible by 5.

How useRef different from useState Hook?

  • Refs return mutable objects with the current property, allowing you to access and manipulate HTML element properties, whereas useState is treated as immutable and does not support the push or pop methods.
  • The useState hook manages stateful values that can change over time while useRef hook stores value that has to persist between renderings.
  • Changing state values causes components to re-render, but refs hold value in memory and have no effect on rendering.
UseState and useRef hooks each provide different functionality, but they can be used together to manage and maintain React components.

Tips and Best Practices for useRef Hook

Here are some points for enhancing user experience with useRef.

  • Prefix the variable name with refs, for example, buttonRef or inputRef. This helps to determine the variable store reference value.
  • You'll enjoy using the useRef hook, but don't overdo it; it's best to handle component functions in the React approach.
  • Somewhat useRef functionality matches the state but avoids refs for state management, as it doesn't trigger re-render.
  • The useRef is used to reference a DOM element, but you should not create a reference during rendering or manipulate DOM directly; instead, use useEffect or events handler to update reference data.

Conclusion

The useRef is one of the crucial hook that let you perform side effects in your react application, such as manipulating the DOM and creating persistent values without triggering the component to re-render, which enhances performance.

However, keep in mind that useRef is not a replacement for the state, so use it correctly and understand its limitations.

You can find more information about useRef hook on official document.

Referencing values with Refs 

Manipulating the DOM with Refs 

useRef

0 Comments:

Post a Comment