Forwarding React Refs with TypeScript
In this post, we cover how to forward React refs with TypeScript.
In the last post, we covered how to use a strongly-typed ref to invoke a method on an HTML element within a React component. What if we want to access an HTML element that isn’t directly in a React component - instead, the HTML element is within a child component.
Let’s imagine we have created a reusable Search
component that wraps an input
element, like in the example below:
function Search() {
return <input type="search" />;
}
When consuming Search
, let’s imagine we want to set focus to the input
element after it has been loaded into the DOM. So, we try to use a ref
and set the focus to the input
element in a useEffect
like below:
function App() {
const input = React.useRef<HTMLInputElement>(null);
React.useEffect(() => {
if (input.current) {
input.current.focus();
}
}, []);
return <Search ref={input} />;
// 💥 - Property 'ref' does not exist on type 'IntrinsicAttributes'
}
This doesn’t work though, and a type error is raised when we reference ref
on the Search
component. 😞
For this to work, we need to forward the ref
to the App
component. We can acheive this with forwardRef
from React:
const Search = React.forwardRef((props, ref) => {
return <input ref={ref} type="search" />;
});
We wrap the Search
component in the forwardRef
function, which does the ref forwarding for us.
This raises a type error though, because ref
is inferred to be of type unknown
. 😞
forwardRef
is a generic function that has type parameters for the type of the ref and the props:
const Component = React.forwardRef<RefType, PropsType>((props, ref) => {
return someComponent;
});
It’s a bit confusing because the ordering of the generic parameters (ref
and then props
) is the opposite of the ordering of the function parameters (props
and then ref
). 😕
Anyway, if we add the generic parameter for the ref
, the type error is resolved:
const Search = React.forwardRef<HTMLInputElement>((props, ref) => {
return <input ref={ref} type="search" />;
});
Note that we don’t need to pass the props’ generic parameter because we don’t have any props in this component.
If you run the CodeSandbox example, we’ll see that focus is set to the input element.
Nice! 😃
Did you find this post useful?
Let me know by sharing it on Twitter.If you to learn more about using TypeScript with React, you may find my course useful: