Component амьдралын мөчлөг
React-н component бол "амьд" зүйл шиг — төрж, өсч, үхдэг. Энэ үйл явцыг lifecycle (амьдралын мөчлөг) гэдэг. Lifecycle-г ойлгосноор useEffect-ийг илүү ухаалгаар хэрэглэж, олон нийтлэг алдаанаас зайлсхийж чадна.
Lifecycle-н гурван үе шат
React component-н амьдралын мөчлөг гурван үндсэн үе шаттай:
1. Mount — component DOM-д нэмэгдэх үе. Зөвхөн нэг удаа болдог.
2. Update — props эсвэл state өөрчлөгдөх болгон component дахин рендерлэгдэх үе. Олон удаа болж болно.
3. Unmount — component DOM-оос хасагдах үе. Зөвхөн нэг удаа болдог.
import { useState, useEffect } from "react";
function Timer() {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
// 🟢 Mount — component DOM-д гарсны дараа ажилладаг
console.log("Timer mount боллоо");
const id = setInterval(() => {
setSeconds((s) => s + 1); // 🔄 Update — seconds өөрчлөгдөнө
}, 1000);
return () => {
// 🔴 Unmount — component DOM-оос хасагдахын өмнө ажилладаг
console.log("Timer unmount боллоо");
clearInterval(id); // interval-ийг цэвэрлэх шаардлагатай!
};
}, []); // хоосон array = зөвхөн mount/unmount-д ажилладаг
return <p>Хугацаа: {seconds} секунд</p>;
}
export default function App() {
const [show, setShow] = useState(true);
return (
<div>
<button onClick={() => setShow(!show)}>
{show ? "Нуух" : "Харуулах"}
</button>
{show && <Timer />}
</div>
);
}
"Нуух" товч дарахад Timer unmount болж interval зогсоно. "Харуулах" дарахад дахин mount болж шинэ interval эхэлнэ.
useEffect ба dependency array
useEffect-н хоёр дахь аргумент болох dependency array нь lifecycle-г хянадаг:
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
const [status, setStatus] = useState("Онлайн");
// 1️⃣ Зөвхөн mount-д ажиллана (хоосон array)
useEffect(() => {
console.log("Компонент гарлаа!");
return () => console.log("Компонент явлаа!");
}, []);
// 2️⃣ Mount + userId өөрчлөгдөх болгонд ажиллана
useEffect(() => {
async function fetchUser() {
const res = await fetch(`/api/users/${userId}`);
const data = await res.json();
setUser(data);
}
fetchUser();
}, [userId]);
// 3️⃣ Рендерлэгдэх болгонд ажиллана (array байхгүй)
useEffect(() => {
document.title = `${status} — ${user?.name ?? "..."}`;
});
return (
<div>
<p>{user?.name}</p>
<p>Төлөв: {status}</p>
</div>
);
}
Нийтлэг хэрэглээнүүд
Lifecycle pattern-уудыг практик жишээгээр харцгаая:
import { useState, useEffect } from "react";
function SearchBox() {
const [query, setQuery] = useState("");
const [results, setResults] = useState([]);
const [loading, setLoading] = useState(false);
useEffect(() => {
if (!query.trim()) {
setResults([]);
return;
}
setLoading(true);
// Хэрэглэгч бичихийн дагуу хайлт хийхгүй — 500ms хүлээнэ (debounce)
const timer = setTimeout(async () => {
try {
const res = await fetch(`/api/search?q=${query}`);
const data = await res.json();
setResults(data);
} finally {
setLoading(false);
}
}, 500);
// Cleanup: дараагийн effect ажиллахын өмнө timer-ийг цэвэрлэнэ
return () => {
clearTimeout(timer);
setLoading(false);
};
}, [query]);
return (
<div>
<input
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="Хайх..."
/>
{loading && <p>Хайж байна...</p>}
<ul>
{results.map((r) => (
<li key={r.id}>{r.title}</li>
))}
</ul>
</div>
);
}
Cleanup функц маш чухал — component unmount болоход гүйж байгаа async ажлуудыг зогсоохгүй бол memory leak үүсдэг. Cleanup нь энэ асуудлаас сэргийлдэг.
Дараагийн хичээлд:
Portal гэж юу болохыг сурна — component-н DOM бүтцийн гадна элемент рендерлэх арга. Modal, tooltip, dropdown зэрэгт яагаад Portal ашигладгийг ойлгоно.