React Hooks that will completely 10x your code performance

The Frontend Forge
8 min readFeb 17, 2025

--

React Hooks
React Hooks

As someone who’s been using react for a couple of years now — I’ve had my fair share of performance wahala. You remember those moments you thought you did a good job, then it’s time to demo to the board, and just like that — VILLAGE PEOPLE 🤯… Suddenly the button that worked just fine moments ago is taking unnecessary time to respond!!! 😩😮‍💨

With React, performance na ODOGWU — knowing when to use the hooks are super important, but you see, knowing the right hook to use at the right case scenario is even importanter. It can tell a great deal between an enthusiastic developer and an experienced one.

React 18 and newer versions have introduced some new hooks that are absolute gems. I’ll just be talking about 5 of them that I’ve now incorporated into my day-to-day coding lingua, but trust me, there’re more.

Meanwhile, if you want to know more about some new toolkits React v19 brings and why you should be using it — check out my React 19 breakdown article.

Without further ado, Let’s dive right in 🏊🏼‍♂️

Let me break down these hooks for you, the way I wish React has explained them to us 🕶… ️Just so you know how awesome they actually are.
The docs didn’t do them enough justice — believe me.

1. useTransistion Hook: The Smooth Operator 🎭

This new React hook is designed to manage state updates in a way that keeps the UI responsive, even during the most complex operations. It’s like having a traffic controller for my component — it prioritizes the most important states updates while maintaining a seamless UI response.

Common use case scenario:
Building a search feature for an e-commerce project where users type in a search box and the results update as they type. This hook comes in handy in preventing UI freeze and lags during fast typing

function ProductSearch() {
const [searchQuery, setSearchQuery] = useState('');
const [isPending, startTransition] = useTransition();
const [searchResults, setSearchResults] = useState([]);

const handleSearch = (event) => {
const query = event.target.value;

// Immediate UI update - high priority
setSearchQuery(query);

// Wrap data fetching in startTransition - lower priority
startTransition(() => {
// This won't block the UI while processing
fetch(`/api/search?query=${query}`)
.then(response => response.json())
.then(data => {
// Update results in background
setSearchResults(data);
});
});
};

return (
<div>
{/* Input always stays responsive */}
<input
type="text"
value={searchQuery}
onChange={handleSearch}
placeholder="Search for products..."
/>

{/* Show loading state while transition is pending */}
{isPending ? (
<p>Searching products...</p>
) : (
<ul>
{searchResults.map(product => (
<li key={product.id}>{product.name}</li>
))}
</ul>
)}
</div>
);
}

While useTransition helps us manage UI updates smoothly, sometimes we need to be more optimistic about our updates. That’s where our next hook comes in…

2. useOptimistic: The Confidence King 👑

As with most applications we build, we have to deal with API Calls and of course, we all want a smooth UX without all those irritating loading skeletons and spinners scattered everywhere. This is where useOptimistic shines bright.

This hook updates UI immediately while the backend catches up — Imagine the “like” buttons, the comment sections. Yh, use useOptimistic hook there.

Common use case scenario:
Let’s build a simple Social Like Button component in a breeze.

import React, { useState } from 'react';
import { useOptimistic } from 'react';


function LikeButton({ postId }) {
const [likes, setLikes] = useState(0);
const [optimisticLikes, setOptimisticLikes] = useOptimistic(likes);

const handleLike = async () => {
// Update the UI immediately
setOptimisticLikes(optimisticLikes + 1);

try {
// Simulate an API call to update likes on the server
await fakeApiCallToLikePost(postId);
// On success, update the actual state
setLikes(optimisticLikes + 1);
} catch (error) {
// Revert the optimistic update if the API call fails
setOptimisticLikes(optimisticLikes);
console.error('Failed to like the post:', error);
}
};

return (
<button onClick={handleLike}>
Like {optimisticLikes}
</button>
);
}

// Simulated API call function
function fakeApiCallToLikePost(postId) {
return new Promise((resolve, reject) => {
setTimeout(() => {
// Simulate a successful response
resolve();
}, 1000);
});
}

export default LikeButton;

Think of useOptimistic as a specialized tool that handles all the edge cases and complexities of optimistic updates, while useState is a more general-purpose tool that would require additional code to handle complex scenarios safely like race conditions, auto-rollback chain

Now that we’ve handled immediate UI feedback, let’s talk about managing heavy computational tasks without blocking the UI…

3. useDeferredValue: The Patient Friend ⏰

Yup, say hello to my patient hook friend… You see those situations where you’re typing in a search box and the app is trying to filter through 1000+ items? Just call in my patient friend.
It will manage all those expensive re-renders efficiently, it shines brightest in components like search interfaces that involves large lists.

Common use case scenario:
Back to the e-commerce app example, now users have to search through a large catalog list — without talking to an api or have varying states.

import React, { useState, useDeferredValue } from 'react';

function SearchList({ items }) {
const [query, setQuery] = useState('');
const deferredQuery = useDeferredValue(query);

const filteredItems = items.filter(item =>
item.toLowerCase().includes(deferredQuery.toLowerCase())
);

return (
<div>
<input
type="text"
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="Search items..."
/>
<ul>
{filteredItems.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
</div>
);
}

Speaking of user interactions, if I don’t talk about hooks help with form handling, it’s all still child’s play.. Yh, those trouble makers of applications…😖

4. useFormStatus: The Form Whisperer 📝

Take this from someone who’s had to build countless forms, this hook is the MVP we all have been waiting for.
Shout-out to the tanstack query for holding the fort — but Baba don show now.

useFormStatus effortlessly tracks form submission states, handles loading state, while ensuring a smooth form UX.

  • This hook must be used within a child component of a <form>
  • It returns pending , data , method and action props
  • Works with React’s form actions.

pending : Boolean flag indicating if the form is currently submitting or not

data : FormData object containing current form values during submission

method : The form’s HTTP method (‘GET’ or ‘POST’)

action : Reference to the form’s submission handler function

Common use case scenario:
I want to create a simple feedback form on a webpage for an event I recently had and I really don’t want to install react query or all those complex query handler just for a simple feedback form.

import { useFormStatus } from "react-dom";

// ✅ useFormStatus works here - child component of <form>
function SubmitButton() {
const { pending } = useFormStatus();
return (
<button
type="submit"
disabled={pending}
className="px-4 py-2 bg-blue-500 text-white rounded disabled:bg-blue-300"
>
{pending ? "Sending..." : "Submit Feedback"}
</button>
);
}

function FeedbackForm() {
// ❌ useFormStatus won't work here - must be in a child component
// const { pending } = useFormStatus(); // This would cause an error!

async function handleSubmit(formData: FormData) {
await new Promise(resolve => setTimeout(resolve, 1000));

const feedback = {
name: formData.get('name'),
rating: formData.get('rating'),
comments: formData.get('comments')
};

console.log('Submitted feedback:', feedback);
alert('Thank you for your feedback!');
}

return (
<form action={handleSubmit} className="max-w-md mx-auto space-y-4 p-4">
{/* ❌ useFormStatus won't work directly in JSX here */}

<div>
<label htmlFor="name" className="block mb-1">Name</label>
<input
type="text"
id="name"
name="name"
required
className="w-full p-2 border rounded"
/>
</div>

<div>
<label htmlFor="rating" className="block mb-1">Rating</label>
<select
id="rating"
name="rating"
required
className="w-full p-2 border rounded"
>
<option value="">Select rating</option>
<option value="5">Excellent</option>
<option value="4">Good</option>
<option value="3">Average</option>
<option value="2">Fair</option>
<option value="1">Poor</option>
</select>
</div>

<div>
<label htmlFor="comments" className="block mb-1">Comments</label>
<textarea
id="comments"
name="comments"
required
className="w-full p-2 border rounded"
rows={4}
/>
</div>

{/* ✅ SubmitButton works because it's a child component */}
<SubmitButton />

{/* ✅ Could also create other child components that use useFormStatus */}
{/* <LoadingIndicator /> */}
{/* <FormStatus /> */}
</form>
);
}

export default FeedbackForm;

Signup forms, login forms, feedback forms… they are great, but what about complex, multi-step forms with validations???

That’s where our final hook comes in…

5. useActionState: The State Wizard 🧙‍♂️

Let’s talk about the last helper hook I sprinkle here and there in my code… Seriously, this hook is ‘that state helper you didn’t know you needed’ till it shows up

This wizard of a hook combines form submission handling with state management — Yes! Imagine Our Confidence King 👑 & Our Form Whisperer 📝 coming together to form one massive Voltron 🤖

It provides a streamlined way to handle form actions while maintaining the resulting state.

Our wizard returns 3 elements: state — Holds the current state/result, formAction — The function to handle form Submissions, and isPending — to tel you when the action is ongoing

Common use case scenario:
To better understand what it does, imagine working on a job application form, where each step needs server validation before moving forward 🧐
Yhh… that kind where you need to validate the email before letting them fill out their work experience, and maybe even check their experience before moving on to the final submission stage.
You’re already imagining the state management nightmare right??

Let’s bring in the wizard himself to demystify this nightmare 🪄

function JobApplicationForm() {
const [formState, formAction, isPending] = useActionState(
async (prev, formData) => {
// Current form state structure
// prev = {
// step: 1,
// data: { email: '', experience: '', etc... },
// errors: null
// }

try {
switch (prev.step) {
case 1: // Email validation step
const email = formData.get('email');
const isEmailValid = await validateEmail(email);

if (!isEmailValid) {
return {
...prev,
errors: { email: 'Email already registered' }
};
}

return {
step: 2,
data: { ...prev.data, email },
errors: null
};

case 2: // Experience validation step
const experience = formData.get('experience');
const isExperienceValid = await validateExperience(experience);

if (!isExperienceValid) {
return {
...prev,
errors: { experience: 'Invalid experience format' }
};
}

return {
step: 3,
data: { ...prev.data, experience },
errors: null
};

// Add more steps as needed
}
} catch (error) {
re4};
}
},
{ step: 1, data: {}, errors: null } // Initial state
);

return (
<form action={formAction} className="space-y-4">
{/* Step 1: Email */}
{formState.step === 1 && (
<div>
<h2>Step 1: Email Verification</h2>
<input
type="email"
name="email"
defaultValue={formState.data.email}
className="border p-2 rounded"
/>
{formState.errors?.email && (
<p className="text-red-500">{formState.errors.email}</p>
)}
</div>
)}

{/* Step 2: Experience */}
{formState.step === 2 && (
<div>
<h2>Step 2: Work Experience</h2>
<textarea
name="experience"
defaultValue={formState.data.experience}
className="border p-2 rounded"
/>
{formState.errors?.experience && (
<p className="text-red-500">{formState.errors.experience}</p>
)}
</div>
)}

<button
disabled={isPending}
className="bg-blue-500 text-white px-4 py-2 rounded"
>
{isPending ? 'Validating...' : 'Continue'}
</button>
</form>
);
}

From the scenario above, you can deduce that the hook looks something like this:

const [state, formAction, isPending] = useActionState(fn, initialState, permalink?);

Finally, My Brethren;

I’ve spent a while in this React world, long enough to know when something’s a game-changer, and these hooks??? They’re the real deal. They’ve helped me turn some of my bogus components into knights in shining armor.

If you’re still here at this point, you’re probably serious about leveling up your react game. Trust me, start with these hooks, experiment with them — build simple case components, break things (Trust me, that’s my specialty 😅), and watch your apps transform.

Got questions? Hit me up in the comments! Let’s grow together. 🚀

See you on the next one! Peace Out ✌️

--

--

The Frontend Forge
The Frontend Forge

Written by The Frontend Forge

Sharpen your frontend skills at The Frontend Forge! 🔥 Join me as I break down JS, TS, React, Vue, React Native, & Next.js with insightful articles & tuts. 💻

No responses yet