React provides powerful built-in hooks like useState
, useReducer
, and useEffect
to manage state and side effects. But what about useRef
? In this article, we will explore how to use the React useRef hook, complete with practical examples. We’ll also break down the key differences between useRef and useState, and show you how to integrate React useRef with TypeScript to avoid common type errors.
What is React useRef Hook?
The React useRef hook is a built-in hook that allows you to persist values across renders without causing re-renders. It is commonly used to reference DOM elements and store mutable values.
Basic Usage
Here's how you can use useRef in a React functional component:
.jsx
1import React, { useRef } from 'react'; // import useRef
2
3function MyComponent() {
4const myRef = useRef(null); // Creating a ref
5
6// Accessing the current value of the ref
7console.log(myRef.current);
8
9return <div ref={myRef}>Basic Example of useRef</div>;
10}
11
In the above example, we create a ref called myRef and attach it to a DOM element using the ref attribute. You can access the current value of the ref using myRef.current.
Usage of useRef hook with TypeScript
The useRef hook is simple to use but becomes even more powerful when paired with TypeScript. Here’s how you can get started:
-
Import useRef
First, import useRef from React:
.tsx
1import { useRef } from 'react';
-
Create a Ref
Next, create a ref using useRef. With TypeScript, you’ll need to specify the type of the ref (e.g., HTMLInputElement for an input field):
.tsx
1const inputRef = useRef<HTMLInputElement>(null); 2// Refs are initially set to null because the DOM element doesn’t exist yet.
-
Attach the Ref to a DOM Element
Pass the ref to the ref attribute of a DOM element:
.tsx
1<input ref={inputRef} type="text" />
-
Access the Ref
Use ref.current to access the DOM element or stored value:
.tsx
1const focusInput = () => { 2 inputRef.current?.focus(); // Focus the input field 3 };
Example: Focus an Input Field
Here’s a complete example of using useRef hook with TypeScript to focus an input field:
.tsx
1import { useRef } from 'react';
2
3function App() {
4const inputRef = useRef<HTMLInputElement>(null);
5
6const focusInput = () => {
7 inputRef.current?.focus();
8};
9
10return (
11 <div>
12 <input ref={inputRef} type="text" placeholder="Type something..." />
13 <button onClick={focusInput}>Focus Input</button>
14 </div>
15);
16}
17
18export default App;
Key Points to Remember
- TypeScript Generics: Always specify the type of your ref (e.g., HTMLInputElement, number, etc.).
- Initial Value: Initialize refs with null for DOM elements.
- Optional Chaining: Use ? to safely access ref.current.
Advanced useRef Examples
Expand beyond the basics with real-world use cases:
-
Tracking Previous State:
Sometimes, you need to know the previous value of a state or prop in React. Since state updates are asynchronous, you can’t directly compare the current and previous values. This is where react useRef hook comes in hand.
How It Works
- useRef persists values between renders without triggering re-renders.
- You can store the previous value in a ref and update it after the state changes.
Example: Tracking Previous State
.tsx
1import { useState, useRef, useEffect } from 'react'; 2 3 function App() { 4 const [count, setCount] = useState<number>(0); 5 const prevCountRef = useRef<number>(0); 6 7 useEffect(() => { 8 prevCountRef.current = count; // Update the ref with the current value 9 }, [count]); // Run this effect whenever count changes 10 11 return ( 12 <div> 13 <p>Current Count: {count}</p> 14 <p>Previous Count: {prevCountRef.current}</p> 15 <button onClick={() => setCount(count + 1)}>Increment</button> 16 </div> 17 ); 18 } 19 20 export default App;
Explanation
- State: count holds the current value.
- Ref: prevCountRef stores the previous value.
- Effect: After count changes, the effect updates prevCountRef.current with the new value.
Common Mistakes and Fixes with useRef
While useRef is a powerful tool, it’s easy to make mistakes if you’re not careful. Here are some common pitfalls of using useRef hook with TypeScript and how to fix them:
-
ref.current is null
Mistake: Trying to access ref.current before the DOM element is ready.Fix: Use optional chaining (?.) to safely access ref.current:.tsx
1const inputRef = useRef<HTMLInputElement>(null); 2inputRef.current.focus(); // Error: current is null
Why It Happens: Refs are initialized with null and only get assigned when the DOM element is rendered..tsx
1inputRef.current?.focus(); // No error if current is null
-
Overusing useRef for State Management
Mistake: Using useRef to store values that should trigger re-renders.Fix: Use useState for values that affect the UI:.tsx
1const countRef = useRef<number>(0); 2countRef.current += 1; // No re-render, UI won't update
Why It Happens: useRef doesn’t trigger re-renders, so it’s not suitable for state that should update the UI..tsx
1const [count, setCount] = useState<number>(0); 2setCount(count + 1); // Triggers re-render
-
Forgetting to Clean Up Refs
Mistake: Not cleaning up refs (e.g., intervals, timeouts) when the component unmounts.Fix: Always clean up refs in the useEffect cleanup function:.tsx
1const timerRef = useRef<number | null>(null); 2 3useEffect(() => { 4timerRef.current = setInterval(() => { 5console.log('Timer running'); 6}, 1000); 7}, []); 8 9// No cleanup: Memory leak!
Why It Happens: Failing to clean up can lead to memory leaks and unexpected behavior..tsx
1useEffect(() => { 2const timer = setInterval(() => { 3 console.log('Timer running'); 4}, 1000); 5 6timerRef.current = timer; 7return () => clearInterval(timer); // Cleanup 8}, []);
useRef vs useState: Use Cases
useRef:
- Access DOM elements (e.g., focus an input field or control a video player).
- Persist mutable values without triggering re-renders (e.g., previous state values).
- Integrate with third-party libraries (e.g., animations or charting libraries).
- Store a timer ID (e.g., setInterval or setTimeout).
useState:
- Track form input values (e.g., text fields, checkboxes, or dropdowns).
- Toggle UI state (e.g., show/hide a modal or toggle a button’s active state).
- Manage dynamic data that requires re-renders (e.g., counters, to-do lists).
- Control component behavior based on state changes (e.g., fetching data when a button is clicked).
Check also SEO strategies to Boost website ranking.
Frequently Asked Questions
-
Q: What is useRef in React?
A: useRef is a React hook that lets you persist values between renders without triggering re-renders. It’s commonly used to access DOM elements, store mutable values, and integrate with third-party libraries.
-
Q: How is useRef different from useState?
A: useRef persists values without triggering re-renders, while useState manages state that triggers re-renders when updated. Use useRef for DOM access and useState for UI state management.
-
Q: Why is my useRef value not updating?
A: useRef doesn’t trigger re-renders, so changes to ref.current won’t update the UI. If you need re-renders, use useState instead.
-
Q: Why is useRef current null?
A: Refs are initialized with null and only get assigned when the DOM element is rendered. Use optional chaining (?.) to safely access ref.current.
If you found this blog helpful, feel free to share it with others who may benefit from it!