এটাই useEffect-এর সবচেয়ে সাধারণ বাস্তব ব্যবহার: ডেটা fetch করা render-এর সময় একটি কম্পোনেন্টের করার মতো কিছু নয় (render-কে JSX-এর একটি pure হিসাব থাকতে হবে) — এটি একটি side effect যা কম্পোনেন্ট render হয়েছে বলে ঘটে, effect ঠিক এটার জন্যই।
তিনটি state — ডেটা নিজেই, এটা এখনও লোড হচ্ছে কিনা, আর যেকোনো error — সাথে effect-এর ভেতরে একটি fetch কল, JavaScript Fetch API পাঠ থেকে ইতিমধ্যে জানা fetch() আর async/await ব্যবহার করে:
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
setLoading(true);
fetch(`/api/users/${userId}`)
.then((res) => res.json())
.then((data) => setUser(data))
.catch((err) => setError(err.message))
.finally(() => setLoading(false));
}, [userId]);
if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {error}</p>;
return <h1>{user.name}</h1>;
}dependency হিসেবে [userId] এখানে নির্দিষ্টভাবে গুরুত্বপূর্ণ: এটা ছাড়া, effect শুধু একবারই fetch করে, চিরকালের জন্য — একটি ভিন্ন ব্যবহারকারীর প্রোফাইলে বদলালে প্রথম ব্যবহারকারীর ডেটা দেখাতেই থাকবে।
প্রথম রিকোয়েস্ট শেষ হওয়ার আগেই userId আবার বদলালে, বা কম্পোনেন্টটি পুরোপুরি unmount হয়ে গেলে, আগের রিকোয়েস্টের ফলাফল তখনও এসে ভুলভাবে এমন state আপডেট করতে পারে যা আর প্রযোজ্য নয়। (useEffect পাঠ থেকে) একটি cleanup ফ্ল্যাগ এটা থেকে রক্ষা করে:
useEffect(() => {
let ignore = false;
setLoading(true);
fetch(`/api/users/${userId}`)
.then((res) => res.json())
.then((data) => {
if (!ignore) setUser(data); // skip if this effect is stale
})
.finally(() => {
if (!ignore) setLoading(false);
});
return () => {
ignore = true; // marks this specific request as stale
};
}, [userId]);effect ফাংশন নিজে async হতে পারে না (এটা একটি cleanup ফাংশনের বদলে একটি Promise রিটার্ন করবে), তাই একটি ভেতরের ফাংশন প্রচলিত সমাধান:
useEffect(() => {
async function loadUser() {
const res = await fetch(`/api/users/${userId}`);
const data = await res.json();
setUser(data);
}
loadUser();
}, [userId]);