useRef is a React Hook that lets you reference a value that’s not needed for rendering.
constref =useRef(initialValue)Reference
useRef(initialValue)
CalluseRef at the top level of your component to declare aref.
import{useRef}from'react';
functionMyComponent(){
constintervalRef =useRef(0);
constinputRef =useRef(null);
// ...Parameters
initialValue: The value you want the ref object’scurrentproperty to be initially. It can be a value of any type. This argument is ignored after the initial render.
Returns
useRef returns an object with a single property:
current: Initially, it’s set to theinitialValueyou have passed. You can later set it to something else. If you pass the ref object to React as arefattribute to a JSX node, React will set itscurrentproperty.
On the next renders,useRef will return the same object.
Caveats
- You can mutate the
ref.currentproperty. Unlike state, it is mutable. However, if it holds an object that is used for rendering (for example, a piece of your state), then you shouldn’t mutate that object. - When you change the
ref.currentproperty, React does not re-render your component. React is not aware of when you change it because a ref is a plain JavaScript object. - Do not writeor read
ref.currentduring rendering, except forinitialization. This makes your component’s behavior unpredictable. - In Strict Mode, React willcall your component function twice in order tohelp you find accidental impurities. This is development-only behavior and does not affect production. Each ref object will be created twice, but one of the versions will be discarded. If your component function is pure (as it should be), this should not affect the behavior.
Usage
Referencing a value with a ref
CalluseRef at the top level of your component to declare one or morerefs.
import{useRef}from'react';
functionStopwatch(){
constintervalRef =useRef(0);
// ...useRef returns aref object with a singlecurrent property initially set to theinitial value you provided.
On the next renders,useRef will return the same object. You can change itscurrent property to store information and read it later. This might remind you ofstate, but there is an important difference.
Changing a ref does not trigger a re-render. This means refs are perfect for storing information that doesn’t affect the visual output of your component. For example, if you need to store aninterval ID and retrieve it later, you can put it in a ref. To update the value inside the ref, you need to manually change itscurrent property:
functionhandleStartClick(){
constintervalId =setInterval(()=>{
// ...
},1000);
intervalRef.current =intervalId;
}Later, you can read that interval ID from the ref so that you can callclear that interval:
functionhandleStopClick(){
constintervalId =intervalRef.current;
clearInterval(intervalId);
}By using a ref, you ensure that:
- You canstore information between re-renders (unlike regular variables, which reset on every render).
- Changing itdoes not trigger a re-render (unlike state variables, which trigger a re-render).
- Theinformation is local to each copy of your component (unlike the variables outside, which are shared).
Changing a ref does not trigger a re-render, so refs are not appropriate for storing information you want to display on the screen. Use state for that instead. Read more aboutchoosing betweenuseRef anduseState.
Example 1 of 2:Click counter
This component uses a ref to keep track of how many times the button was clicked. Note that it’s okay to use a ref instead of state here because the click count is only read and written in an event handler.
import{useRef}from'react';exportdefaultfunctionCounter(){letref =useRef(0);functionhandleClick(){ref.current =ref.current +1;alert('You clicked ' +ref.current +' times!');}return(<buttononClick={handleClick}> Click me!</button>);}
If you show{ref.current} in the JSX, the number won’t update on click. This is because settingref.current does not trigger a re-render. Information that’s used for rendering should be state instead.
Pitfall
Do not writeor readref.current during rendering.
React expects that the body of your componentbehaves like a pure function:
- If the inputs (props,state, andcontext) are the same, it should return exactly the same JSX.
- Calling it in a different order or with different arguments should not affect the results of other calls.
Reading or writing a refduring rendering breaks these expectations.
functionMyComponent(){
// ...
// 🚩 Don't write a ref during rendering
myRef.current =123;
// ...
// 🚩 Don't read a ref during rendering
return<h1>{myOtherRef.current}</h1>;
}You can read or write refsfrom event handlers or effects instead.
functionMyComponent(){
// ...
useEffect(()=>{
// ✅ You can read or write refs in effects
myRef.current =123;
});
// ...
functionhandleClick(){
// ✅ You can read or write refs in event handlers
doSomething(myOtherRef.current);
}
// ...
}If youhave to reador write something during rendering,use state instead.
When you break these rules, your component might still work, but most of the newer features we’re adding to React will rely on these expectations. Read more aboutkeeping your components pure.
Manipulating the DOM with a ref
It’s particularly common to use a ref to manipulate theDOM. React has built-in support for this.
First, declare aref object with aninitial value ofnull:
import{useRef}from'react';
functionMyComponent(){
constinputRef =useRef(null);
// ...Then pass your ref object as theref attribute to the JSX of the DOM node you want to manipulate:
// ...
return<inputref={inputRef}/>;After React creates the DOM node and puts it on the screen, React will set thecurrent property of your ref object to that DOM node. Now you can access the<input>’s DOM node and call methods likefocus():
functionhandleClick(){
inputRef.current.focus();
}React will set thecurrent property back tonull when the node is removed from the screen.
Read more aboutmanipulating the DOM with refs.
Example 1 of 4:Focusing a text input
In this example, clicking the button will focus the input:
import{useRef}from'react';exportdefaultfunctionForm(){constinputRef =useRef(null);functionhandleClick(){inputRef.current.focus();}return(<><inputref={inputRef}/><buttononClick={handleClick}> Focus the input</button></>);}
Avoiding recreating the ref contents
React saves the initial ref value once and ignores it on the next renders.
functionVideo(){
constplayerRef =useRef(newVideoPlayer());
// ...Although the result ofnew VideoPlayer() is only used for the initial render, you’re still calling this function on every render. This can be wasteful if it’s creating expensive objects.
To solve it, you may initialize the ref like this instead:
functionVideo(){
constplayerRef =useRef(null);
if(playerRef.current ===null){
playerRef.current =newVideoPlayer();
}
// ...Normally, writing or readingref.current during render is not allowed. However, it’s fine in this case because the result is always the same, and the condition only executes during initialization so it’s fully predictable.
Deep Dive
If you use a type checker and don’t want to always check fornull, you can try a pattern like this instead:
functionVideo(){
constplayerRef =useRef(null);
functiongetPlayer(){
if(playerRef.current !==null){
returnplayerRef.current;
}
constplayer =newVideoPlayer();
playerRef.current =player;
returnplayer;
}
// ...Here, theplayerRef itself is nullable. However, you should be able to convince your type checker that there is no case in whichgetPlayer() returnsnull. Then usegetPlayer() in your event handlers.
Troubleshooting
I can’t get a ref to a custom component
If you try to pass aref to your own component like this:
constinputRef =useRef(null);
return<MyInputref={inputRef}/>;You might get an error in the console:
By default, your own components don’t expose refs to the DOM nodes inside them.
To fix this, find the component that you want to get a ref to:
exportdefaultfunctionMyInput({value,onChange}){
return(
<input
value={value}
onChange={onChange}
/>
);
}And then addref to the list of props your component accepts and passref as a prop to the relevant childbuilt-in component like this:
functionMyInput({value,onChange,ref}){
return(
<input
value={value}
onChange={onChange}
ref={ref}
/>
);
};
exportdefaultMyInput;Then the parent component can get a ref to it.
Read more aboutaccessing another component’s DOM nodes.