The React Hook Everyone Forgets
In case you have a job in this era of AI (which is a little hard), and your company is using react for the Frontend. Although you must be vibe coding your way through it, but i guess this is the best time to learn actual things in case you haven’t till now. I will be writing these blogs going through small things like these in deep so that I am not afraid of writing code with my hands in an interview.
Today we are going to talk about useRef hook, the almost most commonly used hook but still not a lot of people are clear about it’s actual use case. Well one of the reason for that is we are almost vibe coding our way through everything so who cares. Okay, it’s time to get technical now. We are going to build a video player while to go through the actual real world use case of this hook. Imagine you are given this task in an interview of a 100k job and this is the last round, so if you pass you get the job. It’s a do or die situation for you, so we gotta pass this no matter what. Let’s go.
To start we would need to initialize a react app for this, I am going to start with the extreme basics, so let’s run this command and start.
npm create vite@latestIt would ask you a few choices, so just go through them and start a react + typescript app. Okay, so to start we need to add a video tag and render that.
import React, { useState } from 'react'
import './App.css'
function App() {
// This will be in the future used to update the state of the video element from anywhere
// -without triggering a re-render
const videoRef = React.useRef(null)
return (
<div>
<video ref={videoRef} width="400"
src="https://www.w3schools.com/html/mov_bbb.mp4"
style={{ display: "block", marginBottom: 12 }}
/>
</div>
)
}
export default AppNow, if you run this and go to the 5173 port on your browser, you will see a video playing. So a very basic next task in a video player is a play/pause button. Now if you are aware about the useState hook and someone asks you to build this play/pause button the first thought in your mind will be using this hook. But the problem with useState is that it re-renders the application whenever the value stored in it changes and the other problem is you cannot store any DOM element in it. useState only supports storing data and unfortunately a DOM element is not actually data. So, we need something else to store the DOM element of this video tag, so that whenever someone clicks on a button we are able to change the state of this video tag.
import React, { useState } from 'react'
import './App.css'
function App() {
const [isPlaying,setIsplaying] = useState(false);
const videoRef = React.useRef(null)
const togglePlay = () => {
if(isPlaying) {
videoRef.current.pause()
} else {
videoRef.current.play()
}
setIsplaying(!isPlaying);
}
return (
<div>
<video ref={videoRef} width="400"
src="https://www.w3schools.com/html/mov_bbb.mp4"
style={{ display: "block", marginBottom: 12 }}
/>
<button onClick={togglePlay}>
{isPlaying ? "PAUSE" : "PLAY"}
</button>
</div>
)
}
export default AppIf you have a look at the code we added, it is just a button which is triggering a function and in that function we first check what is the current state of the video i.e if it is playing or it is stopped and then accordingly update the state to the opposite value, now this is where the videoRef is useful to us. Because one of them most useful thing about this useRef is that it does not trigger re-renders no matter how much the value of it is changed, and also just in case there is a re-render that state of the useRef stays the same across the re-renders.
Now, let’s implement another feature in our video player, a mute/unmute button. Now, for this we essentially do not require a useRef but things get tricky when the user have a volume slider as well in this button (which is a required feature). So, suppose the user mutes the video and at that moment the volume was 0.5, but when the user unmute the volume should be able to get back to the same amount. So, we need a way to remember what was the last volume at which the user muted so that we can set the volume to that same amount i.e we need a way to store a value and it should not change across re-renders until the value is explicitly changed. This is where again the useRef is used.
import React, { useState } from 'react'
import './App.css'
function App() {
const [isPlaying,setIsplaying] = useState(false);
const [isMuted,setIsmuted] = useState(false)
const [volume, setVolume] = useState(1);
const videoRef = React.useRef(null)
const lasVolRef = React.useRef(volume)
const togglePlay = () => {
if(isPlaying) {
videoRef.current.pause()
} else {
videoRef.current.play()
}
setIsplaying(!isPlaying);
}
const toggleMute = () =>{
if(isMuted) {
videoRef.current.muted = false;
setVolume(lasVolRef.current)
} else {
videoRef.current.muted = true;
setVolume(0)
}
setIsmuted(!isMuted)
}
const handleVolumeChange = (e) => {
videoRef.current.volume = e.target.value
setVolume(e.target.value)
lasVolRef.current = volume
}
return (
<div>
<video ref={videoRef} width="400"
src="https://www.w3schools.com/html/mov_bbb.mp4"
style={{ display: "block", marginBottom: 12 }}
/>
<input
type="range" min={0} max={1} step={0.05}
value={volume}
onChange={handleVolumeChange}
/>
<button onClick={toggleMute}>
{isMuted ? "MUTED" : "LISTEN"}
</button>
<button onClick={togglePlay}>
{isPlaying ? "PAUSE" : "PLAY"}
</button>
</div>
)
}
export default AppAgain, as you can see we used two useState to store the current state because we need to show that on the frontend so, these should update the values.
So, this is how useRef is useful in maintaining a state across re-renders. Some other usecases of this would be when you want highlight the search bar when someone opens a modal, for this usecase as well you would need to store the DOM element of this input tag as well (the search bar).
Here is a link to the completed component: Github
