⚛️ Demystifying React’s Types: Ref types

⚛️ Demystifying React’s Types: Ref types

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:

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:

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:

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. Its type is defined as:

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.

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:

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.

Here’s an example of using React.ForwardedRef:

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:

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.

Leave a Reply

Your email address will not be published. Required fields are marked *