⚛️ Demystifying React's Types: Ref types
Tags: webdev, react, typescript, javascript
Published: 2024-05-01 12:27:23

When working with TypeScript in ReactJS, using refs in functional components requires a bit of extra care to ensure type safety. In this article, we'll explore the most popularly used and relevant types of refs available in TypeScript-based functional components.

## 1️⃣ `React.RefObject`

The `React.RefObject` type is the most common way to work with refs in functional components. It's used when you create a ref using the `useRef` hook and want to access the current value of the ref. A readonly ref container where the `current` property cannot be mutated.

Here's an example of using `React.RefObject`:

```tsx
import { useRef } from 'react';

export const MyComponent = () => {
  const inputRef = useRef<HTMLInputElement>(null);

  const handleClick = () => {
    inputRef.current?.focus();
  };

  return (
    <div>
      <input type="text" ref={inputRef} />
      <button onClick={handleClick}>Focus Input</button>
    </div>
  );
};
```

In this example, we create a ref called `inputRef` using the `useRef` hook and specify the type as `HTMLInputElement`.

Do not here that when using `useRef`, if the initially passed value is `null`, TypeScript will automatically understand it as a `React.RefObject`. If you want it to be `React.MutableRefObject` AND the initial value to be `null`, the simple trick is to simply define it as:

```typescript
const inputRef = useRef<HTMLInputElement | null>(null);
```

## 2️⃣ `React.MutableRefObject`

The `React.MutableRefObject` type is similar to `React.RefObject`, but it allows the `current` property of the ref to be mutable. This can be useful in scenarios where you need to update the ref's value directly, without triggering a re-render.

Here's an example of using `React.MutableRefObject`:

```tsx
import { useRef } from 'react';

export const MyComponent = () => {
  const counterRef = useRef<number>(0);

  const handleClick = () => {
    counterRef.current++;
    console.log('Counter value:', counterRef.current++);
  };

  return (
    <div>
      <button onClick={handleClick}>Increment Counter</button>
    </div>
  );
};
```

## 3️⃣ `React.RefCallback`

The `React.RefCallback` type is used when you need to access the DOM element or React component at a specific point in time, such as when the component mounts or unmounts. This can be particularly useful when you're working with third-party libraries that require direct DOM access, or when you need to perform complex DOM manipulations, or when you need to [manage a list of refs](https://react.dev/learn/manipulating-the-dom-with-refs#how-to-manage-a-list-of-refs-using-a-ref-callback). Its type is defined as:

```typescript
type RefCallback<T> = (instance:  T  |  null) =>  void;
```

Below is an example of using `React.RefCallback` to measure the size of an element and update the component's state accordingly. This can be useful in scenarios where you need to implement responsive layouts or dynamic UI elements.

```tsx
import { useState, useCallback } from 'react';

export const MyComponent = () => {
  const [elementSize, setElementSize] = useState<{ width: number; height: number }>({
    width: 0,
    height: 0,
  });

  const handleElementRef: React.RefCallback<HTMLDivElement> = useCallback((element) => {
    if (!element) return;
    
    const { offsetWidth, offsetHeight } = element;
  
    setElementSize({ width: offsetWidth, height: offsetHeight });
  }, []);

  return (
    <div ref={handleElementRef}>
      <p>Element size: {elementSize.width} x {elementSize.height}</p>
    </div>
  );
};
```

## 4️⃣ `React.Ref`

`React.Ref` is basically a union type of all possible shapes for React refs. You can understand it as:

```typescript
type  Ref<T> = RefCallBack<T> |  RefObject<T> |  null;
```

## 5️⃣ `React.ForwardedRef`

The `React.ForwardedRef` type is used when you need to forward a ref from a parent component to a child component. This is particularly useful when you're working with reusable components and need to access the underlying DOM element or React component, or if there's a custom ref object created in the child component using [`useImperativeHandle`](https://react.dev/reference/react/useImperativeHandle).

Here's an example of using `React.ForwardedRef`:

```tsx
import { forwardRef, Ref } from 'react';

interface InputProps {
  value: string;
  onChange: (value: string) => void;
}

const InputBase = ({ value, onChange }: InputProps, ref: React.ForwardedRef<HTMLInputElement>) => {
  return (
    <input
      type="text"
      value={value}
      onChange={(e) => onChange(e.target.value)}
      ref={ref}
    />
  );
});

export const Input = forwardRef(InputBase);
```

In this example, we use the `forwardRef` function to create a ref-forwarding component, which allows the parent component to access the underlying `input` element.

## 6️⃣ `React.LegacyRef`

The `React.LegacyRef` type is used when you need to work with refs in a way that is compatible with older versions of React. This type is primarily used for class-based components, which are less common in modern React development.

It's important to note that the `ref` property of every primitive HTML element in React currently has the type `React.LegacyRef<HTMLElementType>`. This means that if you're working with a `div` element, the type of the `ref` property will most likely be `React.LegacyRef<HTMLDivElement>`.

You actually wouldn't have to care about this type at all in your React projects.

## 🏁 Conclusion

In this article, we've explored the most popular types of refs available in React, including `React.RefObject`, `React.MutableRefObject`, `React.RefCallback`, `React.Ref`, `React.ForwardedRef`, and `React.LegacyRef`. By understanding these types, you'll be more confident navigating a React project written in TypeScript. Stay tuned for more articles on React and TypeScript, where we'll dive into the latest features and best practices for building robust and scalable applications.

In case you think it was a good read, you'll probably find my previous post useful as well:

{% link https://dev.to/itswillt/organizing-code-in-a-react-component-4coa %}

---

If you're interested in Frontend Development and Web Development with ReactJS in general, follow me and check out my articles in the profile below.

{% user itswillt %}