Mastering 'useRef' in React with TypeScript: 4 Different Use-Cases for 'useRef'

kirubelkinfe

Kirubel Kinfe

Posted on September 2, 2023

Mastering 'useRef' in React with TypeScript: 4 Different Use-Cases for 'useRef'

In React, useRef is a versatile hook that allows developers to interact with the DOM and manage mutable values without triggering re-renders. When combined with TypeScript, it becomes even more powerful, providing type safety and preventing common runtime errors. In this article, we will explore the various use cases of useRef in React, with a focus on using it effectively in TypeScript projects.

Understanding useRef
The useRef hook in React provides access to a mutable object known as a "ref." This ref can hold a reference to a DOM element or any other value and persists across renders. Unlike state variables, changing the value of a ref does not trigger a re-render of the component, making it ideal for certain scenarios.

Basic Usage
Here's how you can use useRef in a functional component:

import React, { useRef } from 'react';

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

  // Accessing the current value of the ref
  console.log(myRef.current);

  return <div ref={myRef}>Hello, useRef!</div>;
}
Enter fullscreen mode Exit fullscreen mode

In the above example, we create a ref called myRef and attach it to a DOM element using the ref attribute. You can access the current value of the ref using myRef.current.

Use Cases for useRef in React and TypeScript
1. Accessing DOM Elements
One of the most common use cases for useRef is to gain direct access to DOM elements. This is useful for tasks like focusing an input field or measuring the dimensions of an element:

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

function AutoFocusInput() {
  const inputRef = useRef<HTMLInputElement | null>(null);

  useEffect(() => {
    inputRef.current?.focus();
  }, []);

  return <input ref={inputRef} />;
}
Enter fullscreen mode Exit fullscreen mode

In this example, inputRef allows us to focus the input element when the component mounts, without needing a state variable to trigger a re-render.

2. Storing Previous Values
useRef can be used to store and compare previous values across renders. This is useful for detecting changes in props or state:

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

function ValueChangeDetector(props: { value: number }) {
  const prevValueRef = useRef<number | undefined>();

  useEffect(() => {
    if (prevValueRef.current !== undefined && prevValueRef.current !== props.value) {
      console.log('Value changed:', prevValueRef.current, '->', props.value);
    }

    prevValueRef.current = props.value;
  }, [props.value]);

  return <div>{props.value}</div>;
}
Enter fullscreen mode Exit fullscreen mode

Here, prevValueRef stores the previous value of the value prop, allowing us to compare it and take action when it changes.

3. Storing Unmanaged Values
useRef can be used to store values that do not trigger re-renders when they change. This is useful for caching expensive calculations or values that are not part of the component's state:

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

function ExpensiveComponent() {
  const expensiveValueRef = useRef<number>(0);
  const [count, setCount] = useState<number>(0);

  const calculateExpensiveValue = () => {
    if (expensiveValueRef.current === 0) {
      // Perform expensive calculation
      expensiveValueRef.current = /* ... */;
    }
    return expensiveValueRef.current;
  };

  return (
    <div>
      <p>Expensive Value: {calculateExpensiveValue()}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

In this example, expensiveValueRef stores the result of an expensive calculation, ensuring that the calculation only occurs once.

4. Interacting with Third-Party Libraries
When integrating React with third-party libraries or APIs that rely on mutable values, useRef can be used to maintain references and interact with those libraries safely:


import React, { useRef, useEffect } from 'react';
import { Chart } from 'chart.js';

function ChartComponent(props: { data: number[] }) {
  const chartRef = useRef<HTMLCanvasElement | null>(null);
  const chartInstance = useRef<Chart | null>(null);

  useEffect(() => {
    if (chartRef.current) {
      chartInstance.current = new Chart(chartRef.current, {
        type: 'line',
        data: {
          labels: [...Array(props.data.length).keys()],
          datasets: [
            {
              label: 'Data',
              data: props.data,
              borderColor: 'blue',
            },
          ],
        },
      });
    }

    return () => {
      if (chartInstance.current) {
        chartInstance.current.destroy();
      }
    };
  }, [props.data]);

  return <canvas ref={chartRef} />;
}
Enter fullscreen mode Exit fullscreen mode

Here, chartRef holds a reference to the canvas element, and chartInstance holds a reference to the Chart instance. We create and destroy the chart safely within the useEffect hook.

Conclusion
The useRef hook in React, when combined with TypeScript, is a powerful tool that allows you to work with mutable values and interact with the DOM efficiently while maintaining type safety. Understanding the various use cases and best practices for useRef will help you write cleaner, more performant React components. Whether you're managing DOM elements, tracking previous values, caching data, or interacting with external libraries, useRef is an invaluable addition to your React toolkit.

💖 💪 🙅 🚩
kirubelkinfe
Kirubel Kinfe

Posted on September 2, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related