React State Management and Routing
When local state is not enough
If many components need the same data, lift state up, or use context and reducers.
Context
import { createContext, useContext, useState } from "react";
const ThemeContext = createContext("light");
export function ThemeProvider({ children }) {
const [theme, setTheme] = useState("light");
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
{children}
</ThemeContext.Provider>
);
}
export const useTheme = () => useContext(ThemeContext);
useReducer for complex updates
function cartReducer(state, action) {
switch (action.type) {
case "add":
return [...state, action.item];
case "remove":
return state.filter((i) => i.id !== action.id);
case "clear":
return [];
default:
return state;
}
}
// const [cart, dispatch] = useReducer(cartReducer, []);
// dispatch({ type: "add", item });
Data fetching states
Always model loading, error and success.
import { useEffect, useState } from "react";
export function useFetch(url) {
const [state, setState] = useState({ data: null, error: null, loading: true });
useEffect(() => {
const controller = new AbortController();
setState({ data: null, error: null, loading: true });
fetch(url, { signal: controller.signal })
.then((r) => (r.ok ? r.json() : Promise.reject(new Error(`HTTP ${r.status}`))))
.then((data) => setState({ data, error: null, loading: false }))
.catch((error) => {
if (error.name !== "AbortError") setState({ data: null, error, loading: false });
});
return () => controller.abort();
}, [url]);
return state;
}
For production apps consider a data library (TanStack Query, SWR) that adds caching, retries and de-duplication.
Routing with React Router
import { BrowserRouter, Routes, Route, Link, useParams } from "react-router-dom";
function Post() {
const { id } = useParams();
return <h1>Post {id}</h1>;
}
export default function App() {
return (
<BrowserRouter>
<nav>
<Link to="/">Home</Link> | <Link to="/posts/1">Post 1</Link>
</nav>
<Routes>
<Route path="/" element={<h1>Home</h1>} />
<Route path="/posts/:id" element={<Post />} />
<Route path="*" element={<h1>Not found</h1>} />
</Routes>
</BrowserRouter>
);
}
Choosing a state tool
| Need | Use |
|---|---|
| Component-only data | useState |
| Shared across a subtree, rarely changes | Context |
| Complex update logic | useReducer |
| Server data (cache, refetch) | TanStack Query / SWR |
| Large app-wide client state | Zustand, Redux Toolkit |
Loading Comments...