Back to Blog
May 1, 2026
4 min readUpdated: May 10, 2026

Handling State in Modern React Applications

Do you have a question or doubt about something?

Scroll down to the bottom to ask your question, and I or anyone else will respond!

Handling State in Modern React Applications

🧠 Quick Summary (2-3 sentences)

The days of monolithic state management are over. In 2026, the key to a maintainable React app is splitting state into four distinct categories: Local, Global UI, Server Cache, and URL state. This post provides the definitive guide on choosing the right tool for each category without bloating your bundle.


🔴 What Most People Get Wrong

Most developers reach for a "Global State Store" (like Redux) for everything. They store user profiles, form inputs, and even "isOpen" modal states in one massive object.

This is a performance disaster. 90% of what you think is "Global State" is actually just "Server Cache." If you use a tool like React Query for your data fetching, you can delete 80% of your Redux/Zustand code instantly.

📊 State Management Decision Matrix

State TypeExampleBest ToolWhy?
Local UIIs dropdown open?useStateSimple, fast, isolated.
Complex FormMulti-step checkoutuseReducerHandles complex logic without external deps.
Server CacheUser profile, FeedReact QueryHandles refetching, caching, and stale-while-revalidate.
Global UITheme (Dark/Light)ZustandLightweight, no boilerplate, easy to test.
URL StatePage filters, SearchuseSearchParamsDeep-linkable and survives page refreshes.

🟢 Deep Dive

🚀 1. The Rise of Zustand

Redux has its place in massive enterprises, but for 99% of apps, Zustand is the winner. It has zero "Providers" (no more wrapper hell), a tiny footprint, and a simple hooks-based API.

🔄 2. Treat your API as a Cache, not a Store

Stop putting your useEffect fetch results into your global store. Tools like TanStack Query (React Query) manage the lifecycle of your server data so you don't have to.

🔗 3. The URL is your Source of Truth

If a user filters a list and clicks "Share," the recipient should see the same filters. Storing these in a state variable instead of the URL is a common junior mistake.


✅ Step-by-Step Implementation

Step 1: Implement a Global UI Store (Zustand)

Don't use Context for things that change frequently. Use Zustand for better performance.

# Install Zustand
npm install zustand
// store/useThemeStore.ts
import { create } from 'zustand';

interface ThemeState {
  isDarkMode: boolean;
  toggleTheme: () => void;
}

export const useThemeStore = create<ThemeState>((set) =&gt; ({
  isDarkMode: false,
  toggleTheme: () =&gt; set((state) =&gt; ({ isDarkMode: !state.isDarkMode })),
}));

Step 2: Implement Server State (React Query)

Let the library handle the loading, error, and caching states for you.

# Install TanStack Query
npm install @tanstack/react-query
// hooks/useUser.ts
import { useQuery } from '@tanstack/react-query';

export const useUser = (id: string) =&gt; {
  return useQuery({
    queryKey: ['user', id],
    queryFn: () =&gt; fetch(`/api/users/${id}`).then(res =&gt; res.json()),
    staleTime: 5 * 60 * 1000, // Cache for 5 minutes
  });
};

Step 3: Use URL Params for Filters

Always make your UI states shareable via the URL.

// components/SearchFilter.tsx
import { useRouter, useSearchParams } from 'next/navigation';

export const SearchFilter = () =&gt; {
  const router = useRouter();
  const searchParams = useSearchParams();

  const handleSearch = (term: string) =&gt; {
    const params = new URLSearchParams(searchParams);
    params.set('q', term);
    router.push(`?${params.toString()}`);
  };

  return <input onChange={(e) =&gt; handleSearch(e.target.value)} /&gt;;
};

📊 The 80/20 Rule / Quick Wins

The 80% of state management bugs can be fixed by keeping state as local as possible. Before you move a variable to a store or context, ask: "Does any other component actually need this?" If not, keep it in useState.


📚 Resources for Further Reading

LibraryPurpose
Zustand DocsLightweight global state
TanStack QueryThe standard for server state
JotaiAtomic state for complex UIs

🎯 Your Action Item

Audit your app today. Identify one piece of "Server Data" that you are manually storing in a global store and migrate it to React Query. You'll likely delete 20-30 lines of boilerplate code in the process.

Was this helpful?

Discussion

0

Do you have a question or any doubt?

Ask here and I or anyone else will respond!

Loading comments...
2B

By 2BigDev

Full-Stack Engineer