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;
123456789101112131415161718
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'. ...
123
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
12345
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);
123
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);
123
TIP: As a best practice, always initialize useRef to null for HTML elements.
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;
123456789101112131415161718
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 }, []);
12345678
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
1234567891011
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;
12345678910111213141516171819
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> ); ..
12345678910
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 ); ...
123456789
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!);
123
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