The useState()
Hook
The bread and butter of every React developer. A hook used to manage the state of our application (client) and re-render components when state changes.
The useRef()
Hook
A hook that allows you to step outside of the React concept (UI being tied to states, i.e., state changes causing re-renders) and persist values.
Do you know the difference between the two hooks? If yes, are you aware of the nuances and when to use one over the other? If not, don’t worry; you’re in the right place. And for those who have a deep understanding of these hooks, Boss I greet ooh!
The useState()
Hook Declaration with Example
import React, { useState } from 'react';
const App = () => {
const [greeting, setGreeting] = useState(" World");
console.log(`Hello${greeting}!`);
return (<p>Hello{greeting}!</p>);
};
When the greeting variable above changes, it triggers a re-render of the entire App component..
Some use Case of the useState()
hook
- Capturing form inputs: Typically done using controlled inputs, where the input value is tied to the component's state, and changes to the input field update the state accordingly.
import React, { useState } from 'react';
const ControlledInput = () => {
const [inputValue, setInputValue] = useState('');
const handleChange = (e) => {
setInputValue(e.target.value);
};
return (
<div>
<input type="text" value={inputValue} onChange={handleChange} />
<p>Current Input: {inputValue}</p>
</div>
);
};
export default ControlledInput;
The ControlledInput
component uses state to manage the text input's value. Any change to the input field updates the state, with the state updating the displayed value.
- Show or Hide Components: e.g Modals. tool-tip, drop-down e.t.c.
import React, { useState } from 'react';
const Modal = () => {
const [isModalVisible, setIsModalVisible] = useState(false);
const toggleModal = () => {
setIsModalVisible(!isModalVisible);
};
return (
<div>
<button onClick={toggleModal}>
{isModalVisible ? 'Hide' : 'Show'} Modal
</button>
{isModalVisible && (
<div className="modal">
<p>This is a modal!</p>
<button onClick={toggleModal}>Close</button>
</div>
)}
</div>
);
};
export default Modal;
The Modal
component uses state to toggle the visibility of a modal. Clicking the button updates the state, which shows or hides the modal.
- Dynamic styling or rendering components.
import React, { useState } from 'react';
const ShowRed = () => {
const [isRed, setIsRed] = useState(false);
const toggleColor = () => {
setIsRed(!isRed);
};
return (
<div>
<button onClick={toggleColor}>Toggle Color</button>
<p style={{ color: isRed ? 'red' : 'blue' }}>
This text changes color!
</p>
</div>
);
};
export default ShowRed;
The ShowRed
component toggles text color between red and blue based on the state variable isRed
. Clicking the button changes the state, which updates the text color dynamically.
-
Counters: A classic and popular use case of the
useState
hook. You’ll often see this example in almost every React tutorial to demonstrate basic state management.
import React, { useState } from 'react';
const Counter = () => {
const [count, setCount] = useState(0);
return (
<div>
<h1>Count: {count}</h1>
<button onClick={() => setCount(count + 1)}>Increment</button>
<button onClick={() => setCount(count - 1)}>Decrement</button>
</div>
);
};
export default Counter;
The Counter
component displays a count value and provides buttons to increment or decrement it. Clicking the buttons updates the state, which re-renders the component with the new count.
The useRef() hook declaration with example
import React, { useRef } from 'react';
const App = () => {
const greetingRef = useRef("World");
console(`Hello ${greeting}!`);
return (<p>Hello{greeting}!</p>)
//=> Hello World!
When the greetingRef
variable above changes it doesn't triggers the re-rendering of the entire App component.
Some use Case of the useRef() hook
- Accessing DOM Elements:
import React, { useRef } from 'react';
const Input = () => {
const inputRef = useRef(null);
const handleFocus = () => {
inputRef.current.focus();
};
return (
<div>
<input ref={inputRef} type="text" />
<button onClick={handleFocus}>Focus Input</button>
</div>
);
};
export default Input;
The Input
component uses the useRef
hook to access a DOM element directly. Clicking the "Focus Input" button triggers handleFocus
, which sets focus to the input field using the inputRef
.
-
Storing Mutable Values to Avoid Triggering Re-renders: Another alternative is using the
useMemo()
or declaring the variable outside the component.
import React, { useState, useRef, useEffect } from 'react';
const Timer = () => {
const [seconds, setSeconds] = useState(0);
const intervalRef = useRef();
useEffect(() => {
intervalRef.current = setInterval(() => {
setSeconds(prevSeconds => prevSeconds + 1);
}, 1000);
return () => clearInterval(intervalRef.current);
}, []);
return <div>Seconds: {seconds}</div>;
};
export default Timer;
The Timer
component uses the useRef
hook to store the interval ID and avoid re-renders. setInterval
updates the seconds state every second, and the intervalRef
ensures that the interval is cleared on component unmount.
- Persisting Form Input State: Achieved with uncontrolled inputs, where the value is accessed directly from the DOM via a ref. This allows the input field to operate independently of the component's state and avoids triggering re-renders.
import React, { useRef } from 'react';
const Form = () => {
const nameRef = useRef(null);
const handleSubmit = (e) => {
e.preventDefault();
console.log('Name:', nameRef.current.value);
};
return (
<form onSubmit={handleSubmit}>
<input ref={nameRef} type="text" placeholder="Enter your name" />
<button type="submit">Submit</button>
</form>
);
};
export default Form;
The Form
component uses the useRef
hook to manage form input as an uncontrolled input. The form value is accessed directly from the DOM using nameRef
when submitted, without triggering re-renders.
- Giving Access to Native HTML Elements DOM to a Hook, Function, or Package:
import React, { useEffect, useRef } from 'react';
import { gsap } from 'gsap';
const AnimatedBox = () => {
const boxRef = useRef(null);
useEffect(() => {
gsap.to(boxRef.current, { x: 100, duration: 2 });
}, []);
return <div ref={boxRef} className="box">Animate me</div>;
};
export default AnimatedBox
The AnimatedBox
component uses the useRef
hook to access a DOM element and animates it with GSAP. The useEffect
hook triggers the animation when the component mounts, moving the element 100 pixels to the right over 2 seconds.
The Difference between the two hooks
-
Purpose:
-
useState
is used for managing stateful values and causing re-renders when these values change. -
useRef
is used for persisting mutable values across renders without causing re-renders.
-
-
Re-rendering:
- Changes to values managed by
useState
will trigger a re-render of the component. - Changes to values managed by
useRef
will not trigger a re-render.
- Changes to values managed by
-
Usage:
- Use
useState
for values that should trigger a re-render when they change (e.g., form inputs, toggles, dynamic data). - Use
useRef
for values that should persist across renders without causing a re-render (e.g., DOM references, interval IDs, previous state values).
- Use
Tips and Tricks for these Hooks
-
When to Use
useState
OveruseRef
:- Use
useState
when you need the UI to update in response to changes in your data. - Use
useRef
when you need to keep track of a value that doesn’t affect the UI or should not cause a re-render.
- Use
-
Combining
useState
anduseRef
:- In some cases, you might use both hooks together. For example, you can use
useRef
to keep track of a previous value anduseState
for the current value, enabling comparisons without unnecessary re-renders.
- In some cases, you might use both hooks together. For example, you can use
import React, { useState, useRef, useEffect } from 'react';
const Counter = () => {
const [count, setCount] = useState(0);
const prevCountRef = useRef();
useEffect(() => {
// Update the ref with the current count before the component re-renders
prevCountRef.current = count;
}, [count]);
const prevCount = prevCountRef.current;
return (
<div>
<h1>Current Count: {count}</h1>
<h2>Previous Count: {prevCount}</h2>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
};
export default Counter;
The Counter
component uses both useState
and useRef
to track the current and previous count values. useState
manages the current count and triggers re-renders, while useRef
stores the previous count value without causing re-renders.
-
Avoid Overusing
useRef
:- While
useRef
is powerful, it should not be overused. For most state management needs,useState
is the appropriate choice.useRef
is best for specific scenarios where you.
- While
My HNG Internship Experience
Before I conclude, I'd like to talk a little about my ongoing internship at HNG. I joined the Frontend Track with the aim of becoming familiar with building and developing web applications in a team and networking with like-minded individuals. You can learn more about the HNG Internship here and explore opportunities to hire top talents from HNG here. I would like for you guys to join me on this Journey with HNG.
Conclusion
Understanding the difference between useState()
and useRef()
hooks is crucial for building efficient and effective React applications. These hooks serve different purposes and knowing when to use each can greatly enhance your development process.
React Jokes to spice things up.
Why did the React developer break up with his partner?
Because she had too many state issues!
You use useRef
, useState
but you never useBrain
😄.
Top comments (0)