Building Your Learning Module...
Getting things ready for you!
Find videos you like?
Save to resource drawer for future reference!
Simple state management
Complex state management
Professional state management pattern - add, toggle, delete todos!
// Action types
const ACTIONS = {
ADD_TODO: 'add_todo',
TOGGLE_TODO: 'toggle_todo',
DELETE_TODO: 'delete_todo',
FILTER_TODOS: 'filter_todos'
};
// Reducer function
function todosReducer(state, action) {
switch (action.type) {
case ACTIONS.ADD_TODO:
return {
...state,
todos: [
...state.todos,
{
id: Date.now(),
text: action.payload,
completed: false
}
]
};
case ACTIONS.TOGGLE_TODO:
return {
...state,
todos: state.todos.map(todo =>
todo.id === action.payload
? { ...todo, completed: !todo.completed }
: todo
)
};
case ACTIONS.DELETE_TODO:
return {
...state,
todos: state.todos.filter(todo => todo.id !== action.payload)
};
case ACTIONS.FILTER_TODOS:
return {
...state,
filter: action.payload
};
default:
return state;
}
}
// Create Context
const TodoContext = React.createContext();
// Provider Component
function TodoProvider({ children }) {
const [state, dispatch] = React.useReducer(todosReducer, {
todos: [
{ id: 1, text: 'Learn React', completed: false },
{ id: 2, text: 'Master Context', completed: false },
{ id: 3, text: 'Build Projects', completed: false }
],
filter: 'all'
});
const value = { state, dispatch };
return (
<TodoContext.Provider value={value}>
{children}
</TodoContext.Provider>
);
}
// Custom hook for easy access
function useTodos() {
const context = React.useContext(TodoContext);
if (!context) {
throw new Error('useTodos must be used within TodoProvider');
}
return context;
}
// Add Todo Component
function AddTodo() {
const [input, setInput] = React.useState('');
const { dispatch } = useTodos();
const handleSubmit = (e) => {
e.preventDefault();
if (input.trim()) {
dispatch({ type: ACTIONS.ADD_TODO, payload: input });
setInput('');
}
};
return (
<form onSubmit={handleSubmit} className="add-form">
<input
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="Add new todo..."
/>
<button type="submit">Add</button>
</form>
);
}
// Filter Buttons
function Filters() {
const { state, dispatch } = useTodos();
return (
<div className="filters">
<button
className={state.filter === 'all' ? 'active' : ''}
onClick={() => dispatch({ type: ACTIONS.FILTER_TODOS, payload: 'all' })}
>
All
</button>
<button
className={state.filter === 'active' ? 'active' : ''}
onClick={() => dispatch({ type: ACTIONS.FILTER_TODOS, payload: 'active' })}
>
Active
</button>
<button
className={state.filter === 'completed' ? 'active' : ''}
onClick={() => dispatch({ type: ACTIONS.FILTER_TODOS, payload: 'completed' })}
>
Completed
</button>
</div>
);
}
// Todo List
function TodoList() {
const { state, dispatch } = useTodos();
const filteredTodos = state.todos.filter(todo => {
if (state.filter === 'active') return !todo.completed;
if (state.filter === 'completed') return todo.completed;
return true;
});
return (
<div className="todo-list">
{filteredTodos.map(todo => (
<div key={todo.id} className={`todo-item ${todo.completed ? 'completed' : ''}`}>
<input
type="checkbox"
checked={todo.completed}
onChange={() => dispatch({ type: ACTIONS.TOGGLE_TODO, payload: todo.id })}
/>
<span>{todo.text}</span>
<button
onClick={() => dispatch({ type: ACTIONS.DELETE_TODO, payload: todo.id })}
className="delete-btn"
>
×
</button>
</div>
))}
{filteredTodos.length === 0 && (
<p className="empty">No todos to show</p>
)}
</div>
);
}
// Stats
function Stats() {
const { state } = useTodos();
const total = state.todos.length;
const completed = state.todos.filter(t => t.completed).length;
const active = total - completed;
return (
<div className="stats">
<div className="stat">
<strong>{total}</strong>
<span>Total</span>
</div>
<div className="stat">
<strong>{active}</strong>
<span>Active</span>
</div>
<div className="stat">
<strong>{completed}</strong>
<span>Completed</span>
</div>
</div>
);
}
// Root App
function App() {
return (
<TodoProvider>
<div className="app">
<div className="header">
<h2>📝 Todo App</h2>
<p>Context + useReducer Pattern</p>
</div>
<Stats />
<AddTodo />
<Filters />
<TodoList />
</div>
</TodoProvider>
);
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);Loading preview...
Better for complex state with multiple actions
Create useTodos hook for cleaner code
Define constants for better maintainability
Reducer ensures consistent state updates