javascript
327 lines · 2 tabs
Alex Chang
Feb 2026
2 tabs
import React, { createContext, useContext, useReducer, useState } from 'react';
// 1. Basic Context
const UserContext = createContext(null);
function UserProvider({ children }) {
const [user, setUser] = useState(null);
const login = (userData) => setUser(userData);
const logout = () => setUser(null);
const value = {
user,
login,
logout,
isAuthenticated: !!user,
};
return (
<UserContext.Provider value={value}>
{children}
</UserContext.Provider>
);
}
// Custom hook for using context
function useUser() {
const context = useContext(UserContext);
if (!context) {
throw new Error('useUser must be used within UserProvider');
}
return context;
}
// Usage
function LoginButton() {
const { login, logout, isAuthenticated, user } = useUser();
return isAuthenticated ? (
<div>
<span>Welcome, {user.name}</span>
<button onClick={logout}>Logout</button>
</div>
) : (
<button onClick={() => login({ id: 1, name: 'Alex' })}>
Login
</button>
);
}
// 2. Context with useReducer
const CartContext = createContext(null);
const cartReducer = (state, action) => {
switch (action.type) {
case 'ADD_ITEM':
const existing = state.items.find(item => item.id === action.payload.id);
if (existing) {
return {
...state,
items: state.items.map(item =>
item.id === action.payload.id
? { ...item, quantity: item.quantity + 1 }
: item
),
};
}
return {
...state,
items: [...state.items, { ...action.payload, quantity: 1 }],
};
case 'REMOVE_ITEM':
return {
...state,
items: state.items.filter(item => item.id !== action.payload),
};
case 'UPDATE_QUANTITY':
return {
...state,
items: state.items.map(item =>
item.id === action.payload.id
? { ...item, quantity: action.payload.quantity }
: item
),
};
case 'CLEAR_CART':
return { ...state, items: [] };
default:
return state;
}
};
function CartProvider({ children }) {
const [state, dispatch] = useReducer(cartReducer, { items: [] });
const addItem = (item) => dispatch({ type: 'ADD_ITEM', payload: item });
const removeItem = (id) => dispatch({ type: 'REMOVE_ITEM', payload: id });
const updateQuantity = (id, quantity) =>
dispatch({ type: 'UPDATE_QUANTITY', payload: { id, quantity } });
const clearCart = () => dispatch({ type: 'CLEAR_CART' });
const total = state.items.reduce(
(sum, item) => sum + item.price * item.quantity,
0
);
const value = {
items: state.items,
addItem,
removeItem,
updateQuantity,
clearCart,
total,
itemCount: state.items.reduce((sum, item) => sum + item.quantity, 0),
};
return (
<CartContext.Provider value={value}>
{children}
</CartContext.Provider>
);
}
function useCart() {
const context = useContext(CartContext);
if (!context) {
throw new Error('useCart must be used within CartProvider');
}
return context;
}
// 3. Multiple contexts composed
function App() {
return (
<UserProvider>
<CartProvider>
<ThemeProvider>
<MainApp />
</ThemeProvider>
</CartProvider>
</UserProvider>
);
}
// 4. Context with TypeScript-style interface
/*
interface ThemeContextType {
theme: 'light' | 'dark';
toggleTheme: () => void;
}
*/
const ThemeContext = createContext(null);
function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light');
const toggleTheme = () => {
setTheme(prev => prev === 'light' ? 'dark' : 'light');
};
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
}
// Redux Toolkit approach (modern)
import { createSlice, configureStore, createAsyncThunk } from '@reduxjs/toolkit';
// 1. Create slice (actions + reducer together)
const counterSlice = createSlice({
name: 'counter',
initialState: { value: 0 },
reducers: {
increment: (state) => {
state.value += 1; // Immer allows "mutations"
},
decrement: (state) => {
state.value -= 1;
},
incrementByAmount: (state, action) => {
state.value += action.payload;
},
},
});
// Export actions
export const { increment, decrement, incrementByAmount } = counterSlice.actions;
// 2. Async actions with createAsyncThunk
export const fetchUser = createAsyncThunk(
'users/fetchById',
async (userId, { rejectWithValue }) => {
try {
const response = await fetch(`/api/users/${userId}`);
if (!response.ok) throw new Error('Failed to fetch');
return await response.json();
} catch (error) {
return rejectWithValue(error.message);
}
}
);
const usersSlice = createSlice({
name: 'users',
initialState: {
entities: {},
loading: 'idle',
error: null,
},
reducers: {},
extraReducers: (builder) => {
builder
.addCase(fetchUser.pending, (state) => {
state.loading = 'pending';
})
.addCase(fetchUser.fulfilled, (state, action) => {
state.loading = 'succeeded';
state.entities[action.payload.id] = action.payload;
})
.addCase(fetchUser.rejected, (state, action) => {
state.loading = 'failed';
state.error = action.payload;
});
},
});
// 3. Configure store
const store = configureStore({
reducer: {
counter: counterSlice.reducer,
users: usersSlice.reducer,
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: false,
}),
});
// 4. React component using Redux
import { useSelector, useDispatch } from 'react-redux';
function Counter() {
const count = useSelector((state) => state.counter.value);
const dispatch = useDispatch();
return (
<div>
<button onClick={() => dispatch(decrement())}>-</button>
<span>{count}</span>
<button onClick={() => dispatch(increment())}>+</button>
<button onClick={() => dispatch(incrementByAmount(5))}>+5</button>
</div>
);
}
function UserProfile({ userId }) {
const dispatch = useDispatch();
const user = useSelector((state) => state.users.entities[userId]);
const loading = useSelector((state) => state.users.loading);
const error = useSelector((state) => state.users.error);
useEffect(() => {
if (!user) {
dispatch(fetchUser(userId));
}
}, [userId, user, dispatch]);
if (loading === 'pending') return <div>Loading...</div>;
if (error) return <div>Error: {error}</div>;
if (!user) return null;
return <div>{user.name}</div>;
}
// 5. Selectors (memoized with reselect)
import { createSelector } from '@reduxjs/toolkit';
const selectAllTodos = (state) => state.todos.items;
const selectFilter = (state) => state.todos.filter;
export const selectFilteredTodos = createSelector(
[selectAllTodos, selectFilter],
(todos, filter) => {
if (filter === 'active') return todos.filter(t => !t.completed);
if (filter === 'completed') return todos.filter(t => t.completed);
return todos;
}
);
// Usage
function TodoList() {
const todos = useSelector(selectFilteredTodos);
return (
<ul>
{todos.map(todo => (
<li key={todo.id}>{todo.text}</li>
))}
</ul>
);
}
// 6. Classic Redux pattern (for comparison)
// Actions
const INCREMENT = 'counter/increment';
const DECREMENT = 'counter/decrement';
const increment = () => ({ type: INCREMENT });
const decrement = () => ({ type: DECREMENT });
// Reducer
function counterReducer(state = { value: 0 }, action) {
switch (action.type) {
case INCREMENT:
return { ...state, value: state.value + 1 };
case DECREMENT:
return { ...state, value: state.value - 1 };
default:
return state;
}
}
2 files · javascript
Explain with highlit
State management solutions handle data flow in complex applications. I use React Context API for moderate state sharing without prop drilling. The createContext function creates context objects, while Provider passes data down the tree. The useReducer hook manages complex state logic with actions and reducers. Redux provides centralized state management with unidirectional data flow. Actions describe what happened, reducers specify state updates, and store holds application state. The useSelector hook reads state, while useDispatch dispatches actions. Modern Redux Toolkit simplifies boilerplate with createSlice. Proper state management improves maintainability.
Related snips
javascript
// Creating a Promise
const myPromise = new Promise((resolve, reject) => {
const success = true;
setTimeout(() => {
if (success) {
Promises and async/await patterns for asynchronous JavaScript
javascript
promises
async-await
by Alex Chang
1 tab
javascript
import { Controller } from "@hotwired/stimulus"
import Mousetrap from "mousetrap"
export default class extends Controller {
connect() {
// Global shortcuts
Keyboard shortcuts with Stimulus and Mousetrap
stimulus
javascript
ux
by Jordan Lee
2 tabs
typescript
import axios, { AxiosError } from 'axios'
import { v4 as uuidv4 } from 'uuid'
const api = axios.create({
baseURL: import.meta.env.VITE_API_URL || 'http://localhost:3000/api/v1',
timeout: 15000,
Axios API client with interceptors
react
axios
api
by Maya Patel
1 tab
typescript
import { create } from 'zustand'
import { persist } from 'zustand/middleware'
interface FilterState {
search: string
category: string | null
Zustand for lightweight state management
react
zustand
state-management
by Maya Patel
2 tabs
swift
import SwiftUI
struct ContentView: View {
@State private var username = ""
@State private var isLoggedIn = false
@StateObject private var viewModel = LoginViewModel()
SwiftUI declarative UI with state management
swift
swiftui
ios
by Sofia Martinez
2 tabs
javascript
// Get canvas and context
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
// 1. Basic shapes
// Rectangle (filled)
Canvas API for graphics and animations
canvas
javascript
graphics
by Alex Chang
1 tab
Share this code
Here's the card — post it anywhere.