useRef() is similar to useSate() as it allows us to persist(remain unchanged) values between renders but unlike useState(), the Ref
hook does not cause a re-render when the mutable value is changed.
useRef() returns a mutable object whose current property is set with an initial value that is passed as an argument to the Ref function.
const refObject = useRef(initial_value);
In the above example, refObject
is the returned object. This object has a current
property that can be used to obtain the value of the referenced object at any time.
There are two primary uses of useRef() -
- To create persisted mutable variables(these are called refs or references).
- To access DOM elements(or React elements).
Let's dive into these.
1. useRef() to create persisted mutable variables
Trying to count the number of times a component re-renders using useState will lead to an infinite loop as useState itself causes a re-render. This is demonstrated in the example below.
import React,{useState, useEffect} from 'react'
function App() {
const [text, setText] = useState('')
const [count, setCount] = useState(0)
useEffect(() => {
setCount(prevStateCount => prevStateCount + 1)
})
return (
<div>
<input value={text} onChange={e=>setText(e.target.value)} />
<div>Type some text in the box</div>
<div>Component rendered {count} times</div>
</div>
)
}
export default App
During initial component render, the 'count' is incremented which causes the component to re-render, and hence the count increments again leading to re-rendering the component. Essentially this is an infinite loop of incrementing 'count' and component re-rendering.
Refs to the rescue 🛟...
Refs can be used to solve the infinite loop issue that arises due to re-rendering when using the state hook.
import React,{useState, useEffect, useRef} from 'react'
function App() {
const [text, setText] = useState('')
const count = useRef(1)
useEffect(() => {
count.current = count.current + 1
})
return (
<div>
<input value={text} onChange={e=>setText(e.target.value)} />
<div>Type some text in the box</div>
<div>Component rendered {count.current} times</div>
</div>
)
}
export default App
useRef() replaces useState() and count
is an object with a current
property. The current
property persists as it is updated between different renders.
We can observe from the image below, each time a character is entered in the input field, the count increments. Since 'apple' is entered, the count is incremented 6 times (1 on initial render + increment by 1 for each character). Irrespective of the number of times the count changes, our component is not re-rendered since it is decoupled from our component render cycle.
2. Accessing DOM elements
A more common use for Refs is when we need to reference HTML elements.
Every HTML element has a ref
attribute. We can add the ref
attribute to the element to access the element directly in the DOM.
Let's understand this use case with an example. Consider the code for a scenario where we want to focus on an input when a button is clicked.
import React,{useRef} from 'react'
function App() {
const inputRef = useRef()
const focus = () => {
inputRef.current.focus()
}
return (
<div>
<input ref={inputRef} />
<button onClick={focus}>Click to focus</button>
</div>
)
}
export default App
Each time 'inputRef' is rendered on the screen, the 'inputRef' variable is set to the input
element. Therefore, in the focus
function, we are accessing 'inputRef' variable's current property(this corresponds to input
element) and then focussing on it.
From the screenshot attached below, we can observe how clicking on the button focuses on the input.
Another hack with useRef() 💡 -->
Imagine updating the state with every character when dealing with forms. This could be slightly excessive. Using Refs, we can set up a connection between the HTML element that is rendered eventually and other JavaScript code.
👏 Congratulations & great going 👏. You have now covered three React hooks. This would be a good point to re-collect your understanding of these hooks.
If you feel confident 😎, dive straight into Part 4 where I cover useReducer().
Top comments (0)