ReactAdvanced
Real Project: Todo App
useState, useReducer, custom hook, filtering ও localStorage দিয়ে সম্পূর্ণ Todo app — বাংলায়।
9টি অংশবাংলা ভাষায়
প্রজেক্ট ডিজাইন
- Add / remove / toggle todo
- Status filter — All, Active, Completed
- localStorage-এ পার্সিস্ট
- Derived list-এ useMemo
Reducer + custom hook
useTodos — সব logicjsx
jsx
import { useEffect, useReducer } from "react";
const initialState = { todos: [], filter: "all" };
function reducer(state, action) {
switch (action.type) {
case "ADD": {
const todo = { id: crypto.randomUUID(), text: action.text, done: false };
return { ...state, todos: [...state.todos, todo] };
}
case "TOGGLE": {
return {
...state,
todos: state.todos.map((t) =>
t.id === action.id ? { ...t, done: !t.done } : t
),
};
}
case "REMOVE": {
return { ...state, todos: state.todos.filter((t) => t.id !== action.id) };
}
case "FILTER": {
return { ...state, filter: action.filter };
}
default:
return state;
}
}
const STORAGE_KEY = "todos";
function useTodos() {
const [state, dispatch] = useReducer(reducer, initialState, () => {
const stored = localStorage.getItem(STORAGE_KEY);
return stored ? JSON.parse(stored) : initialState;
});
useEffect(() => {
localStorage.setItem(STORAGE_KEY, JSON.stringify(state.todos));
}, [state.todos]);
return { state, dispatch };
}App component
TodoAppjsx
jsx
import { useMemo, useState } from "react";
import { useTodos } from "./useTodos";
function TodoApp() {
const { state, dispatch } = useTodos();
const [text, setText] = useState("");
// derived — filter অনুযায়ী list
const visibleTodos = useMemo(() => {
if (state.filter === "active") {
return state.todos.filter((t) => !t.done);
}
if (state.filter === "completed") {
return state.todos.filter((t) => t.done);
}
return state.todos;
}, [state.todos, state.filter]);
const addTodo = (e) => {
e.preventDefault();
if (!text.trim()) return;
dispatch({ type: "ADD", text: text.trim() });
setText("");
};
return (
<div className="todo-app">
<h1>Todo List</h1>
<form onSubmit={addTodo}>
<input
value={text}
onChange={(e) => setText(e.target.value)}
placeholder="নতুন কাজ…"
/>
<button type="submit">Add</button>
</form>
<div className="filters">
{["all", "active", "completed"].map((f) => (
<button
key={f}
className={state.filter === f ? "active" : ""}
onClick={() => dispatch({ type: "FILTER", filter: f })}
>
{f}
</button>
))}
</div>
<ul>
{visibleTodos.map((todo) => (
<li key={todo.id}>
<input
type="checkbox"
checked={todo.done}
onChange={() => dispatch({ type: "TOGGLE", id: todo.id })}
/>
<span className={todo.done ? "done" : ""}>{todo.text}</span>
<button onClick={() => dispatch({ type: "REMOVE", id: todo.id })}>✕</button>
</li>
))}
</ul>
<p>{visibleTodos.length}টি কাজ</p>
</div>
);
}
export default TodoApp;সারসংক্ষেপ
| চ্যালেঞ্জ | React সমাধান |
|---|---|
| জটিল state logic | useReducer |
| localStorage-এ save | custom hook + useEffect |
| derived list | useMemo |
| forms | controlled input + FormData |
| UI ভাগ করা | Component ও props |
পরবর্তী ধাপ
এখন Next.js-এ একই app বানিয়ে Server Components, Streaming ও Server Actions-এর সাথে মিলিয়ে নিন — পরের ডকুমেন্টেশন।
শেষ প্যারায় নিজে practice করুন — কোড কপি করে নিজের এডিটরে চালিয়ে দেখুন।