DarslarWeb dasturlash
Amaliy loyiha — Class komponentda Todo
Class komponentlar, state, setState, metodlar va lifecycle — hammasi birgalikda. To'liq Todo ilova.
70 daqiqa
React — Dars 9
Todo App — Class Component
Class, state, setState, propsni bolalarga uzatish — React'ning old uslubi bilan real loyiha quramiz.
classstatesetStateprops
Bosqichlar
6 ta mavzu1. Loyiha strukturasi
1src/2├── components/3│ ├── TodoForm.jsx // yangi vazifa qo'shish4│ ├── TodoList.jsx // ro'yxat5│ ├── TodoItem.jsx // bitta vazifa6│ └── Filter.jsx // filtr tugmalari7├── App.jsx // asosiy class8├── App.css9└── main.jsx2. App class — state va metodlar
src/App.jsx
1import React, { Component } from "react";2import TodoForm from "./components/TodoForm";3import TodoList from "./components/TodoList";4import Filter from "./components/Filter";5import "./App.css";6
7class App extends Component {8 state = {9 vazifalar: [],10 filtr: "all", // all | active | done11 };12
13 // Lifecycle — sahifa ochilganda localStorage'dan yuklash14 componentDidMount() {15 const saved = localStorage.getItem("vazifalar");16 if (saved) {17 this.setState({ vazifalar: JSON.parse(saved) });18 }19 }20
21 // Har o'zgarganda saqlash22 componentDidUpdate(prevProps, prevState) {23 if (prevState.vazifalar !== this.state.vazifalar) {24 localStorage.setItem(25 "vazifalar",26 JSON.stringify(this.state.vazifalar)27 );28 }29 }30
31 qoshish = (matn) => {32 const yangi = {33 id: Date.now(),34 matn,35 bajarildi: false,36 };37 this.setState(oldin => ({38 vazifalar: [...oldin.vazifalar, yangi],39 }));40 };41
42 ochir = (id) => {43 this.setState(oldin => ({44 vazifalar: oldin.vazifalar.filter(v => v.id !== id),45 }));46 };47
48 toggle = (id) => {49 this.setState(oldin => ({50 vazifalar: oldin.vazifalar.map(v =>51 v.id === id ? { ...v, bajarildi: !v.bajarildi } : v52 ),53 }));54 };55
56 filtrOzgartir = (yangiFiltr) => {57 this.setState({ filtr: yangiFiltr });58 };59
60 render() {61 const { vazifalar, filtr } = this.state;62
63 // Filtrlash64 const korinadigan = vazifalar.filter(v => {65 if (filtr === "active") return !v.bajarildi;66 if (filtr === "done") return v.bajarildi;67 return true;68 });69
70 const faolSoni = vazifalar.filter(v => !v.bajarildi).length;71
72 return (73 <div className="app">74 <h1>Vazifalarim</h1>75
76 <TodoForm qoshish={this.qoshish} />77
78 <Filter79 joriy={filtr}80 ozgartir={this.filtrOzgartir}81 />82
83 <TodoList84 vazifalar={korinadigan}85 ochir={this.ochir}86 toggle={this.toggle}87 />88
89 <p className="stats">90 {faolSoni} ta bajarilmagan, jami {vazifalar.length}91 </p>92 </div>93 );94 }95}96
97export default App;3. TodoForm — forma
src/components/TodoForm.jsx
1import React, { Component } from "react";2
3class TodoForm extends Component {4 state = { matn: "" };5
6 onChange = (e) => {7 this.setState({ matn: e.target.value });8 };9
10 onSubmit = (e) => {11 e.preventDefault();12 const matn = this.state.matn.trim();13 if (!matn) return;14
15 this.props.qoshish(matn);16 this.setState({ matn: "" });17 };18
19 render() {20 return (21 <form onSubmit={this.onSubmit}>22 <input23 type="text"24 value={this.state.matn}25 onChange={this.onChange}26 placeholder="Yangi vazifa..."27 />28 <button type="submit">Qo'sh</button>29 </form>30 );31 }32}33
34export default TodoForm;4. TodoList + TodoItem
src/components/TodoList.jsx
1import React, { Component } from "react";2import TodoItem from "./TodoItem";3
4class TodoList extends Component {5 render() {6 const { vazifalar, ochir, toggle } = this.props;7
8 if (vazifalar.length === 0) {9 return <p className="empty">Hali vazifa yo'q</p>;10 }11
12 return (13 <ul>14 {vazifalar.map(v => (15 <TodoItem16 key={v.id}17 vazifa={v}18 ochir={ochir}19 toggle={toggle}20 />21 ))}22 </ul>23 );24 }25}26
27export default TodoList;src/components/TodoItem.jsx
1import React, { Component } from "react";2
3class TodoItem extends Component {4 render() {5 const { vazifa, ochir, toggle } = this.props;6
7 return (8 <li className={vazifa.bajarildi ? "done" : ""}>9 <input10 type="checkbox"11 checked={vazifa.bajarildi}12 onChange={() => toggle(vazifa.id)}13 />14 <span>{vazifa.matn}</span>15 <button16 className="del"17 onClick={() => ochir(vazifa.id)}18 >19 ×20 </button>21 </li>22 );23 }24}25
26export default TodoItem;5. Filtrlash
src/components/Filter.jsx
1import React, { Component } from "react";2
3class Filter extends Component {4 render() {5 const { joriy, ozgartir } = this.props;6 const turlari = [7 { id: "all", nom: "Hammasi" },8 { id: "active", nom: "Faol" },9 { id: "done", nom: "Bajarilgan" },10 ];11
12 return (13 <div className="filter">14 {turlari.map(t => (15 <button16 key={t.id}17 className={joriy === t.id ? "active" : ""}18 onClick={() => ozgartir(t.id)}19 >20 {t.nom}21 </button>22 ))}23 </div>24 );25 }26}27
28export default Filter;6. localStorage va lifecycle
App.jsx'dagi componentDidMount — birinchi chizilganda localStorage'dan yuklaydi. componentDidUpdate — vazifalar o'zgarganda saqlaydi. Bu «persistent» ma'lumot effekti beradi.
src/App.css
1* { box-sizing: border-box; margin: 0; padding: 0; font-family: system-ui, sans-serif; }2body { background: #0f172a; color: white; min-height: 100vh; padding: 40px 16px; }3.app { max-width: 540px; margin: 0 auto; background: #1e293b; padding: 28px; border-radius: 16px; }4h1 { margin-bottom: 18px; }5
6form { display: flex; gap: 8px; margin-bottom: 16px; }7form input { flex: 1; padding: 10px 14px; border-radius: 8px; border: 1.5px solid #334155; background: #0f172a; color: white; font-size: 15px; }8form button { padding: 10px 18px; border: none; border-radius: 8px; background: #fbbf24; color: #0f172a; font-weight: 700; cursor: pointer; }9
10.filter { display: flex; gap: 6px; margin-bottom: 16px; }11.filter button { background: transparent; color: #94a3b8; border: 1.5px solid #334155; padding: 6px 12px; border-radius: 8px; font-size: 13px; cursor: pointer; }12.filter button.active { background: #fbbf24; color: #0f172a; border-color: #fbbf24; }13
14ul { list-style: none; }15li { display: flex; align-items: center; gap: 10px; padding: 10px 12px; background: #0f172a; border-radius: 8px; margin-bottom: 6px; }16li.done span { text-decoration: line-through; color: #64748b; }17li span { flex: 1; }18li .del { background: transparent; color: #ef4444; font-size: 20px; border: none; cursor: pointer; padding: 0 8px; }19
20.empty, .stats { text-align: center; color: #64748b; font-size: 13px; margin-top: 12px; }Class Todo — ishlaydigan demo
Natijajonli