useRef

Welcome to our comprehensive guide on useRef hooks in React. In this blog, we will delve into the nuances of useRef, exploring its functionality, use cases, and best practices. Whether you’re a React beginner or an experienced developer, understanding useRef can significantly enhance your component design and performance.

Table of Contents

  1. Introduction to useRef

  2. Syntax and Basic Usage

  3. Common Use Cases

    • Accessing DOM Elements

    • Storing Mutable Values

    • Keeping Reference to Previous Values

  4. Advanced Patterns

    • Integrating with Third-Party Libraries

    • Creating Persistent References

    • Optimizing Performance

  5. Best Practices

  6. Conclusion

1. Introduction to useRef

The useRef hook is part of the React Hooks API, introduced in React 16.8. It provides a way to persist values across renders without causing re-renders. Unlike state, changing a ref does not trigger a component update. This makes useRef ideal for storing mutable values that need to persist between renders.

2. Syntax and Basic Usage

The basic syntax for useRef is straightforward:

import React, { useRef } from 'react';

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

  return (
    <div ref={myRef}>
      {/* Component content */}
    </div>
  );
}

Here, myRef is an object with a single property current, which holds the reference value. Initially, myRef.current is set to initialValue.

3. Common Use Cases

Accessing DOM Elements

One of the primary use cases for useRef is to directly interact with DOM elements:

function TextInputWithFocusButton() {
  const inputEl = useRef(null);

  const onButtonClick = () => {
    // `current` points to the mounted text input element
    inputEl.current.focus();
  };

  return (
    <>
      <input ref={inputEl} type="text" />
      <button onClick={onButtonClick}>Focus the input</button>
    </>
  );
}

Storing Mutable Values

useRef can also be used to store mutable values that persist across renders without causing re-renders:

function Stopwatch() {
  const timerRef = useRef(0);

  const startTimer = () => {
    timerRef.current = setInterval(() => {
      console.log('Tick');
    }, 1000);
  };

  const stopTimer = () => {
    clearInterval(timerRef.current);
  };

  return (
    <div>
      <button onClick={startTimer}>Start</button>
      <button onClick={stopTimer}>Stop</button>
    </div>
  );
}

Keeping Reference to Previous Values

useRef is also useful for keeping track of previous values:

function PreviousValue({ value }) {
  const prevValueRef = useRef();

  useEffect(() => {
    prevValueRef.current = value;
  }, [value]);

  return (
    <div>
      <p>Current: {value}</p>
      <p>Previous: {prevValueRef.current}</p>
    </div>
  );
}

4. Advanced Patterns

Integrating with Third-Party Libraries

When using third-party libraries that manipulate the DOM, useRef can provide direct access to elements:

import { useEffect, useRef } from 'react';
import someLibrary from 'some-library';

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

  useEffect(() => {
    someLibrary.initialize(elementRef.current);
  }, []);

  return <div ref={elementRef}></div>;
}

Creating Persistent References

You can use useRef to create persistent references for callbacks to avoid unnecessary re-renders:

function usePersistentCallback(callback) {
  const callbackRef = useRef(callback);

  useEffect(() => {
    callbackRef.current = callback;
  }, [callback]);

  return (...args) => callbackRef.current(...args);
}

Optimizing Performance

For performance optimization, especially in large lists or complex UIs, useRef can help avoid expensive calculations on each render:

function ExpensiveCalculationComponent({ value }) {
  const prevValueRef = useRef();

  const expensiveCalculation = useCallback(() => {
    // perform expensive calculation
  }, [value]);

  useEffect(() => {
    if (prevValueRef.current !== value) {
      expensiveCalculation();
    }
    prevValueRef.current = value;
  }, [value, expensiveCalculation]);

  return <div>Calculated result</div>;
}

5. Best Practices

  • Avoid Overusing Refs: Use refs sparingly and only when necessary. Overusing refs can lead to less readable and harder-to-maintain code.

  • Do Not Mutate State with Refs: Refs should not replace state for managing dynamic values that affect rendering. Use state for such cases.

  • Clean Up Effects: When using refs with side effects (e.g., intervals, timeouts), always clean up to avoid memory leaks.

6. Conclusion

The useRef hook is a powerful tool in the React ecosystem, offering capabilities that enhance component performance and manage side effects efficiently. By understanding and implementing the use cases and best practices discussed in this guide, you can leverage useRef to build more robust and efficient React applications.

Last updated