In this article, you’ll learn how to use the react.useref () hook to create persistent mutable values (also known as references or refs), and to access DOM elements.

We will explain from the following points:

1. Variable value - 1.1 use case: record button click - 1.2 use case: realize stopwatch 2. Access to DOM elements - 2.1 Use case: Focus input 3. Update reference restrictions 4. conclusionCopy the code

Variable values

The useRef(initialValue) takes a parameter (the initialValue of the reference) and returns a reference (also known as ref). A reference is just an object with the special property current:

const reference = useRef(initialValue);

reference.current; // The current reference
Copy the code

Reference. current accesses the reference and reference.current = newValue updates the reference value:

import { useRef } from 'react';

function MyComponent() {
  const reference = useRef(initialValue);

  const someHandler = () = > {
    // Access a reference
    const value = reference.current;
    // Update the reference value
    reference.current = newValue;
  };
}
Copy the code

There are two things to remember about references:

  1. Referenced values are persisted (unchanged) between component re-renders;
  2. Updating references does not trigger component rerendering.

Now, let’s look at how useRef() is used in practice.

Example: Record button clicks

The logButtonClicked component uses a reference to store the number of clicks on the button:

import { useRef } from 'react';

function LogButtonClicks() {
  const countRef = useRef(0);
  
  const handle = () = > {
    countRef.current++;
    console.log(`Clicked ${countRef.current} times`);
  };

  console.log('I rendered! ');

  return <button onClick={handle}>Click me</button>;
}
Copy the code

Const countRef = useRef(0) creates a reference countRef initialized with 0.

When the button is clicked, handle is called and the reference value is incremented: countref.current ++, which is recorded to the console.

Note that updating the reference value countref.current ++ does not trigger component rerendering. ‘I rendered! ‘is printed only once during the initial render.

Now there’s a legitimate question: What’s the main difference between a reference and a state?

Now there’s a fair question: What’s the main difference between References and State?

Key differences between Reference and state

Let’s reuse the LogButtonclicked component from the previous section, but use the useState() hook to count button clicks:

import { useState } from 'react';

function LogButtonClicks() {
  const [count, setCount] = useState(0);
  
  const handle = () = > {
    const updatedCount = count + 1;
    console.log(`Clicked ${updatedCount} times`);
    setCount(updatedCount);
  };

  console.log('I rendered! ');

  return <button onClick={handle}>Click me</button>;
}
Copy the code

Every time you click, you’ll see “I Rendering!” in the console. ‘– this means that the component is rerendered every time the status is updated.

So, the two main differences between State and References are:

  1. Updating state triggers component rerendering, whereas updating ref does not.
  2. State updates are asynchronous (the state variable is updated after rerendering), whereas ref updates synchronously (the updated value is immediately available)

From a higher perspective, ref is used to store infrastructure data for components, while State stores information that is directly displayed on the screen.

Example: Implementing a stopwatch

What you can store in the REF is infrastructure information that involves some side effects. For example, you can store Pointers of different types in the REF: timer IDS, socket ids, and so on.

For example, the following stopwatch component uses the setInterval(callback, time) timer function to increase each second of the stopwatch counter. The timer ID is stored in a reference timerIdRef:

import { useRef, useState, useEffect } from 'react';

function Stopwatch() {
  const timerIdRef = useRef(0);
  const [count, setCount] = useState(0);

  const startHandler = () = > {
    if (timerIdRef.current) { return; }
    timerIdRef.current = setInterval(() = > setCount(c= > c+1), 1000);
  };

  const stopHandler = () = > {
    clearInterval(timerIdRef.current);
    timerIdRef.current = 0;
  };

  useEffect(() = > {
    return () = > clearInterval(timerIdRef.current); } []);return (
    <div>
      <div>Timer: {count}s</div>
      <div>
        <button onClick={startHandler}>Start</button>
        <button onClick={stopHandler}>Stop</button>
      </div>
    </div>
  );
}
Copy the code

The startHandler() function, called when the Start button is clicked, starts the timer and references timeridRef.current = setInterval(…) Save the timer ID in.

To stop the stopwatch, click the Stop button. The stop button handler () accesses the timer ID from the reference and stops the timer clearInterval(timeridRef.current).

In addition, the useEffect() cleanup function also stops the timer if the component is unloaded while the stopwatch is active.

In the stopwatch example, ref is used to store infrastructure data-the active timer ID.

Accessing DOM elements

Another useful use of the useRef() hook is to access DOM elements. This requires three steps:

  1. Define a reference to access the const elementRef = useRef();

  2. ;

  3. After the reference is complete, elementref. current contains the DOM element.

import { useRef, useEffect } from 'react';

function AccessingElement() {
  const elementRef = useRef();

   useEffect(() = > {
    constdivElement = elementRef.current; } []);return (
    <div ref={elementRef}>
      I'm an element
    </div>
  );
}
Copy the code

Example: Focus input box

import { useRef, useEffect } from 'react';

function InputFocus() {
  const inputRef = useRef();

  useEffect(() = >{ inputRef.current.focus(); } []);return (
    <input 
      ref={inputRef} 
      type="text" 
    />
  );
}
Copy the code

Const inputRef = useRef() creates a reference to hold the input element.

Then assign inputRef to the ref attribute of the input field :.

Then, set inputRef as the input element. You can now programmatically set the focus to the input state: inputref.current.focus ().

Ref is null during initial rendering

At initial rendering, the ref that holds the DOM element is empty:

import { useRef, useEffect } from 'react';

function InputFocus() {
  const inputRef = useRef();

  useEffect(() = > {
    / / output ` HTMLInputElement `
    console.log(inputRef.current); inputRef.current.focus(); } []);// Initialize render with undefined
  console.log(inputRef.current);

  return <input ref={inputRef} type="text" />;
}
Copy the code

React still determines the output of the component during initial rendering, so the DOM structure has not yet been created. That’s why inputRef. Current evaluates to undefined at initial rendering.

As soon as the input element is created in the DOM, the useEffect(callback, []) hook calls the callback function: therefore, the callback function is the correct place to access inputref.current.

Update references restriction

The functional scope of the functional component should evaluate the output or invoke the hook.

This is why updating ref (and updating state) should not be performed in the direct scope of component functions.

Ref must be updated within the useEffect() callback or handler (event handler, timer handler, and so on).

import { useRef, useEffect } from 'react';

function MyComponent({ prop }) {
  const myRef = useRef(0);

  useEffect(() = > {
    myRef.current++; // Good!

    setTimeout(() = > {
      myRef.current++; // Good!
    }, 1000); } []);const handler = () = > {
    myRef.current++; // Good!
  };

  myRef.current++; // Bad!

  if (prop) {
    myRef.current++; // Bad!
  }

  return <button onClick={handler}>My button</button>;
}
Copy the code

conclusion

The useRef() hook stores mutable values (aka References or refs) that are persisted between renders and can also access DOM elements.

Calling const reference = useRef(initialValue) with the initialValue returns a special object called reference. The reference object has a property current: you can use this property to read the reference value, or to update the reference. The reference current = newValue.

Referenced values are persistent between component rerendering.

Update references, as opposed to update status, do not trigger component rerendering.

References can also access DOM elements.

Element

– Elements are available in reference.current.