How to use React useRef in Typescript
Jasser Mark Arioste
In my previous tutorial, I showed you everything you need to know about how to use useState in typescript .
In this beginner guide, I’m going to show you all you need to know about using React’s useRef hook in typescript. When I was new to typescript, I didn’t know how to use useRef. I was encountering errors on how to initialize it when referring to an HTML element.
We’re going start from the very beginning up to the more advanced usage of useRef . At the end of this tutorial, we’ll be able to master how to useRef hook in typescript.
What is the useRef hook?
The useRef hook allows you to persist values between re-renders. When changing its value, it does not trigger a re-render of a component. The most common use case is to store a reference to an HTML element to be able to access its dom API.
How to use the useRef for Basic HTML Elements
Let’s take a look at a basic example. Below, we are setting the focus to the input element when a component renders for the first time.
import React, { useRef, useEffect } from "react";
const Component = () => {
const inputRef = useRef(null);
useEffect(() => {
if (inputRef.current) {
inputRef.current.focus();
}
}, []);
return (
<div>
<input type="text" ref={inputRef} />
</div>
);
};
export default Component;
The code above will be fine for Javascript. But, what are the issues of the above code in typescript?
The result is a compile-time error. The typescript compiler does not know that inputRef.current is an HTML Element.
...
inputRef.current.focus(); //Error: Property 'focus' does not exist on type 'never'.
...
To fix this, we have to declare the type of value we want to store inside useRef by using a generic type parameter . Let’s change our useRef initialization and you’ll see that the error is gone.
...
//const inputRef = useRef(null);
const inputRef = useRef<HTMLInputElement>(null);
...
inputRef.current.focus(); //no error
How to determine the generic type parameter for useRef?
In VSCode Editor, you can see the types of HTML elements if you hover over the ref attribute. Use this, as the type parameter for the useRef hook.
Some examples:
const inputRef = useRef<HTMLInputElement>(null);
const divRef = useRef<HTMLDivElement>(null);
const formRef = useRef<HTMLFormElement>(null);
Type ‘MutableRefObject<HTMLInputElement | undefined>’ is not assignable to type ‘LegacyRef<HTMLInputElement> | undefined’. Error
Sometimes we fail to initialize useRef properly and the error above shows up. Most likely, you did not initialize useRef to null . To fix this, change the following:
//const inputRef = useRef<HTMLInputElement>();
const inputRef = useRef<HTMLInputElement>(null);
Object is possibly ‘null’. Error
React manages the reference for HTML elements and will populate the .current property. We are using inputRef in the input element. React populates this and it should not be null as typescript suggests .
import React, { useEffect, useRef } from "react";
const Component = () => {
const inputRef = useRef<HTMLInputElement>(null);
useEffect(() => {
inputRef.current.focus(); //Object is possibly 'null'
}, []);
return (
<div>
<input type="text" ref={inputRef} />
</div>
);
};
export default Component;
There are three possible solutions to this error.
If we are sure that the reference will not be null as in the example above, we can simply use the non-null assertion operator ! .
...
//const inputRef = useRef<HTMLInputElement>(null);
const inputRef = useRef<HTMLInputElement>(null!);
...
useEffect(() => {
inputRef.current.focus(); //no error
}, []);
Otherwise, the solution is to add a guard if-statement or use the optional chaining operator when accessing the reference.
...
useEffect(() => {
if (inputRef.current) {
inputRef.current.focus(); //no error
}
}, []);
...
//or
inputRef.current?.focus(); //no error
How to use useRef for third-party UI libraries like MUI
Oftentimes, we use third-party libraries like MUI to speed up development. Sometimes, we get stuck when using useRef too due to long typescript errors.
Let’s take a look at a simple example where we want to focus on a Button component after rendering.
import { Button } from "@mui/material";
import React, { useEffect, useRef } from "react";
const Component = () => {
const buttonRef = useRef(null); //no generic type here
useEffect(() => {
if (buttonRef.current) {
buttonRef.current.focus(); //Error: //Property 'focus' does not exist on type 'never'.
}
}, []);
return (
<div>
<Button ref={buttonRef} />
</div>
);
};
export default Component;
To fix the error above, we learned previously that we need to use a generic type parameter. If we try to use a broard type like <HTMLElement> , it will fix the error above but also produces another error.
...
const buttonRef = useRef<HTMLElement>(null);
...
return (
<div>
<Button ref={buttonRef} /> //Error: Type 'RefObject<HTMLElement>' is not assignable to type 'RefObject<HTMLButtonElement>'.
</div>
);
..
Type ‘RefObject<HTMLElement>’ is not assignable to type ‘RefObject<HTMLButtonElement>‘.
This error occurs when we are not using a more specific HTML element or simply the wrong element type.
The solution is already stated in the error itself. We have to change useRef to use <HTMLButtonElement> as type or whatever is stated in the error.
...
const buttonRef = useRef<HTMLButtonElement>(null);
...
return (
<div>
<Button ref={buttonRef} /> //no error
);
...
To avoid this error, you can hover over the ref property of the component and initialize useRef with that specific type.
//we know that the Button ref prop expects a React.RefObject<HTMLButtonElement>
//lets use <HTMLButtonElement> as the type for our useRef hook.
const buttonRef = useRef<HTMLButtonElement>(null!);
Conclusion
We learned the best practices on how to use the useRef hook with typescript. We also learned how to deal with possible errors when using useRef.
If you like this tutorial, please leave a like or share! If you want to get updated on our latest react or javascript tutorials. Subscribe to our newsletter !
Resources
React docs - https://reactjs.org/docs/hooks-reference.html#useref
React Typescript cheat sheet - https://react-typescript-cheatsheet.netlify.app/docs/basic/getting-started/hooks
Credits - Image by David Mark from Pixabay


