# Past, Present, and Future of React State Management

> A comprehensive look at the evolution of state management in React applications, from Redux to React Server Components.

Author: Karan Vijayakumar
Published: 2024-03-10
Tags: react, state-management, frontend, javascript
Reading time: 2 min
Canonical URL: https://karanvk.me/blog/react-state-management

---

## The Evolution of React State Management

State management in React has come a long way since the early days. Let's take a journey through time and explore how we got here, and where we're heading.

## The Past: Redux Era (2015-2019)

### The Problem

In the early days of React, managing state across components was challenging:

```jsx
// The prop drilling nightmare
function App() {
  const [user, setUser] = useState(null);
  const [theme, setTheme] = useState('light');
  const [notifications, setNotifications] = useState([]);
  
  return (
    <Layout 
      user={user} 
      theme={theme}
      notifications={notifications}
      setUser={setUser}
      setTheme={setTheme}
      setNotifications={setNotifications}
    >
      {/* Props passed down through many layers... */}
    </Layout>
  );
}
```

### Redux to the Rescue

Redux introduced a centralized store with predictable state updates:

```javascript
// Redux store setup
const initialState = {
  user: null,
  theme: 'light',
  notifications: []
};

function rootReducer(state = initialState, action) {
  switch (action.type) {
    case 'SET_USER':
      return { ...state, user: action.payload };
    case 'SET_THEME':
      return { ...state, theme: action.payload };
    case 'ADD_NOTIFICATION':
      return { 
        ...state, 
        notifications: [...state.notifications, action.payload]
      };
    default:
      return state;
  }
}
```

### The Redux Boilerplate Problem

While powerful, Redux came with significant boilerplate:

```javascript
// Action types
const SET_USER = 'SET_USER';
const SET_THEME = 'SET_THEME';

// Action creators
const setUser = (user) => ({ type: SET_USER, payload: user });
const setTheme = (theme) => ({ type: SET_THEME, payload: theme });

// Selectors
const selectUser = (state) => state.user;
const selectTheme = (state) => state.theme;

// Connect component (class component era)
const mapStateToProps = (state) => ({
  user: selectUser(state),
  theme: selectTheme(state)
});

const mapDispatchToProps = { setUser, setTheme };

export default connect(mapStateToProps, mapDispatchToProps)(MyComponent);
```

## The Present: Hooks & Modern Solutions (2019-Present)

### React Hooks Changed Everything

The introduction of hooks in React 16.8 revolutionized state management:

```jsx
// Context + Hooks = Simple global state
const UserContext = createContext();

function UserProvider({ children }) {
  const [user, setUser] = useState(null);
  
  const login = async (credentials) => {
    const user = await api.login(credentials);
    setUser(user);
  };
  
  const logout = () => setUser(null);
  
  return (
    <UserContext.Provider value={{ user, login, logout }}>
      {children}
    </UserContext.Provider>
  );
}

// Usage in any component
function Profile() {
  const { user, logout } = useContext(UserContext);
  
  return (
    <div>
      <h1>Welcome, {user.name}</h1>
      <button onClick={logout}>Logout</button>
    </div>
  );
}
```

### Modern State Libraries

#### Zustand - Minimal and Powerful

```javascript
import { create } from 'zustand';

const useStore = create((set) => ({
  user: null,
  theme: 'light',
  setUser: (user) => set({ user }),
  setTheme: (theme) => set({ theme }),
  toggleTheme: () => set((state) => ({ 
    theme: state.theme === 'light' ? 'dark' : 'light'
  }))
}));

// Usage
function ThemeToggle() {
  const { theme, toggleTheme } = useStore();
  return <button onClick={toggleTheme}>{theme}</button>;
}
```

#### Jotai - Atomic State Management

```javascript
import { atom, useAtom } from 'jotai';

// Define atoms
const userAtom = atom(null);
const themeAtom = atom('light');
const isDarkAtom = atom((get) => get(themeAtom) === 'dark');

// Usage
function ThemeIndicator() {
  const [isDark] = useAtom(isDarkAtom);
  return <span>{isDark ? '🌙' : '☀️'}</span>;
}
```

#### React Query / TanStack Query - Server State

```javascript
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';

function UserProfile({ userId }) {
  const queryClient = useQueryClient();
  
  const { data: user, isLoading } = useQuery({
    queryKey: ['user', userId],
    queryFn: () => fetchUser(userId)
  });
  
  const updateMutation = useMutation({
    mutationFn: updateUser,
    onSuccess: () => {
      queryClient.invalidateQueries(['user', userId]);
    }
  });
  
  if (isLoading) return <Spinner />;
  
  return (
    <div>
      <h1>{user.name}</h1>
      <button onClick={() => updateMutation.mutate({ id: userId, name: 'New Name' })}>
        Update Name
      </button>
    </div>
  );
}
```

### State Management Comparison

| Library | Bundle Size | Learning Curve | Best For |
|---------|------------|----------------|----------|
| Redux Toolkit | 11kb | Medium | Large apps with complex state |
| Zustand | 1kb | Low | Simple global state |
| Jotai | 2kb | Low | Atomic, derived state |
| Recoil | 20kb | Medium | Complex derived state |
| React Query | 12kb | Medium | Server state |
| Valtio | 3kb | Low | Mutable state fans |

## The Future: Server Components Era (2024+)

### React Server Components

The paradigm is shifting again with Server Components:

```jsx
// Server Component - No client-side state needed!
async function UserProfile({ userId }) {
  const user = await db.user.findUnique({ where: { id: userId }});
  
  return (
    <div>
      <h1>{user.name}</h1>
      <p>{user.email}</p>
      <UserActions user={user} /> {/* Client Component */}
    </div>
  );
}

// Client Component - Only interactive parts
'use client';
function UserActions({ user }) {
  const [isEditing, setIsEditing] = useState(false);
  
  return (
    <button onClick={() => setIsEditing(true)}>
      Edit Profile
    </button>
  );
}
```

### The New Mental Model

1. **Server State** → Fetched on the server, no client state needed
2. **UI State** → Local useState for component-specific UI
3. **Shared Client State** → Minimal, using Zustand or Context

```jsx
// Modern architecture
// 1. Server Component fetches data
async function Dashboard() {
  const stats = await getStats();
  const notifications = await getNotifications();
  
  return (
    <div>
      <StatsDisplay stats={stats} />
      <NotificationPanel initialData={notifications} />
    </div>
  );
}

// 2. Client component for interactivity
'use client';
function NotificationPanel({ initialData }) {
  // Only client-side UI state
  const [filter, setFilter] = useState('all');
  
  const filtered = useMemo(() => 
    initialData.filter(n => filter === 'all' || n.type === filter),
    [initialData, filter]
  );
  
  return (
    <div>
      <FilterTabs value={filter} onChange={setFilter} />
      <NotificationList items={filtered} />
    </div>
  );
}
```

## Key Takeaways

1. **Start Simple** - Use useState and useContext first
2. **Separate Concerns** - Server state vs client state
3. **Choose the Right Tool** - Match the library to your needs
4. **Embrace Server Components** - They reduce client-side state significantly

## My Recommendations

### For New Projects

```
Small app → useState + Context
Medium app → Zustand + React Query  
Large app → Zustand + React Query + Server Components
```

### Migration Path

```
Redux → Redux Toolkit → Zustand (for client state)
                     → React Query (for server state)
```

## Conclusion

State management has evolved from the Redux boilerplate era to a more flexible, purpose-built approach. With Server Components, we're moving towards a world where most data doesn't need client-side state at all.

The future is simpler, faster, and more intuitive.

## Resources

- [Zustand](https://github.com/pmndrs/zustand)
- [Jotai](https://jotai.org/)
- [TanStack Query](https://tanstack.com/query)
- [React Server Components](https://react.dev/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023)
