Yon effektlarni ishonchli boshqarish uchun React'ning useEffect hook'ining to'liq imkoniyatlarini oching. Ushbu qo'llanma global dasturchilar uchun asosiy tushunchalar, keng tarqalgan shablonlar, ilg'or texnikalar va muhim amaliyotlarni o'z ichiga oladi.
React useEffect'ni o'zlashtirish: Yon effektlarni boshqarish shablonlari bo'yicha to'liq qo'llanma
Zamonaviy veb-dasturlashning dinamik olamida React foydalanuvchi interfeyslarini yaratish uchun kuchli kutubxona sifatida ajralib turadi. Uning komponentga asoslangan arxitekturasi deklarativ dasturlashni rag'batlantiradi, bu esa UI yaratishni intuitiv va samarali qiladi. Biroq, ilovalar kamdan-kam hollarda alohida mavjud bo'ladi; ular ko'pincha tashqi dunyo bilan o'zaro aloqada bo'lishlari kerak ā ma'lumotlarni olish, obunalarni sozlash, DOM'ni manipulyatsiya qilish yoki uchinchi tomon kutubxonalari bilan integratsiya qilish. Bu o'zaro ta'sirlar "yon effektlar" deb nomlanadi.
useEffect hook'i bilan tanishing, bu React'dagi funksional komponentlarning asosidir. React Hooks bilan birga taqdim etilgan useEffect bu yon effektlarni boshqarishning kuchli va elegant usulini taqdim etadi, bu esa avval sinf komponentlarining hayotiy sikl metodlarida (masalan, componentDidMount, componentDidUpdate, va componentWillUnmount) mavjud bo'lgan imkoniyatlarni to'g'ridan-to'g'ri funksional komponentlarga olib keladi. useEffect'ni tushunish va o'zlashtirish shunchaki toza kod yozish emas; bu yanada samarali, ishonchli va qo'llab-quvvatlanishi oson React ilovalarini yaratishdir.
Ushbu to'liq qo'llanma sizni useEffect'ning asosiy tamoyillarini, keng tarqalgan qo'llanilish holatlarini, ilg'or shablonlarini va muhim eng yaxshi amaliyotlarini o'rganish uchun chuqur sayohatga olib chiqadi. Siz tajribali React dasturchisi bo'lib, o'z tushunchangizni mustahkamlashni xohlaysizmi yoki hook'larga yangi bo'lib, ushbu muhim tushunchani o'rganishga intilasizmi, bu yerda qimmatli ma'lumotlarni topasiz. Biz oddiy ma'lumotlarni olishdan tortib murakkab bog'liqliklarni boshqarishgacha bo'lgan hamma narsani ko'rib chiqamiz, bu esa har qanday yon effekt ssenariysini hal qilishga tayyor bo'lishingizni ta'minlaydi.
1. useEffect Asoslarini Tushunish
Asosan, useEffect sizga funksional komponentlarda yon effektlarni bajarishga imkon beradi. U aslida React'ga komponentingiz renderdan keyin biror narsa qilishi kerakligini aytadi. Keyin React sizning "effekt" funksiyangizni DOM'ga o'zgarishlarni yuborganidan so'ng ishga tushiradi.
React'da Yon Effektlar Nima?
Yon effektlar ā bu tashqi dunyoga ta'sir qiluvchi yoki tashqi tizim bilan o'zaro aloqada bo'luvchi operatsiyalardir. React kontekstida bu ko'pincha quyidagilarni anglatadi:
- Ma'lumotlarni olish: Ma'lumotlarni qabul qilish yoki yuborish uchun API so'rovlarini amalga oshirish.
- Obunalar: Hodisa tinglovchilarini sozlash (masalan, foydalanuvchi kiritishi, global hodisalar uchun), WebSocket ulanishlari yoki real vaqtda ma'lumotlar oqimlari.
- DOM Manipulyatsiyasi: Brauzerning Hujjat Ob'ekt Modeli (DOM) bilan bevosita ishlash (masalan, hujjat sarlavhasini o'zgartirish, fokusni boshqarish, React bo'lmagan kutubxonalar bilan integratsiya qilish).
- Taymerlar:
setTimeoutyokisetInterval'dan foydalanish. - Log yozish: Analitik ma'lumotlarni yuborish.
Asosiy useEffect Sintaksisi
useEffect hook'i ikkita argument qabul qiladi:
- Yon effekt mantig'ini o'z ichiga olgan funksiya. Bu funksiya ixtiyoriy ravishda tozalash funksiyasini qaytarishi mumkin.
- Ixtiyoriy bog'liqliklar massivi.
import React, { useEffect, useState } from 'react';
function MyComponent() {
const [count, setCount] = useState(0);
useEffect(() => {
// Bu yon effekt funksiyasi
console.log('Komponent render qilindi yoki count o\'zgardi:', count);
// Ixtiyoriy tozalash funksiyasi
return () => {
console.log('count uchun tozalash:', count);
};
}, [count]); // Bog'liqliklar massivi
return (
<div>
<p>Hisob: {count}</p>
<button onClick={() => setCount(count + 1)}>Oshirish</button>
</div>
);
}
Bog'liqliklar Massivi: Boshqaruv Kaliti
useEffect'ning ikkinchi argumenti, ya'ni bog'liqliklar massivi, effekt qachon ishga tushishini nazorat qilish uchun juda muhimdir. React effektni faqat bog'liqliklar massividagi qiymatlardan birontasi renderlar orasida o'zgargan bo'lsa, qayta ishga tushiradi.
-
Bog'liqliklar massivi yo'q: Effekt komponentning har bir renderidan keyin ishlaydi. Bu ma'lumotlarni olish kabi samaradorlik uchun muhim effektlar uchun kamdan-kam hollarda kerak bo'ladi, chunki bu cheksiz tsikllarga yoki keraksiz qayta ishga tushirishlarga olib kelishi mumkin.
useEffect(() => { // Har bir renderdan keyin ishlaydi }); -
Bo'sh bog'liqliklar massivi (
[]): Effekt faqat birinchi renderdan (mount) keyin bir marta ishlaydi va tozalash funksiyasi komponent o'chirilishidan (unmount) oldin bir marta ishlaydi. Bu faqat bir marta sodir bo'lishi kerak bo'lgan effektlar uchun ideal, masalan, dastlabki ma'lumotlarni olish yoki global hodisa tinglovchilarini sozlash.useEffect(() => { // Mount paytida bir marta ishlaydi console.log('Komponent mount qilindi!'); return () => { // Unmount paytida bir marta ishlaydi console.log('Komponent unmount qilindi!'); }; }, []); -
Qiymatlarga ega bog'liqliklar massivi (
[propA, stateB]): Effekt birinchi renderdan keyin va massivdagi qiymatlardan birontasi o'zgarganda ishlaydi. Bu eng keng tarqalgan va ko'p qirrali qo'llanilish usuli bo'lib, effekt mantig'ingiz tegishli ma'lumotlar o'zgarishlari bilan sinxronlashtirilishini ta'minlaydi.useEffect(() => { // Mount paytida va har doim 'userId' o'zgarganda ishlaydi fetchUser(userId); }, [userId]);
Tozalash Funksiyasi: Xotira Sızıntısı va Xatoliklarning Oldini Olish
Ko'pgina yon effektlar "tozalash" bosqichini talab qiladi. Masalan, agar siz obuna o'rnatsangiz, xotira sızıntısını oldini olish uchun komponent o'chirilganda obunani bekor qilishingiz kerak. Agar siz taymerni boshlasangiz, uni tozalashingiz kerak. Tozalash funksiyasi sizning useEffect callback'ingizdan qaytariladi.
React tozalash funksiyasini effektni qayta ishga tushirishdan oldin (agar bog'liqliklar o'zgarsa) va komponent o'chirilishidan oldin ishga tushiradi. Bu resurslarning to'g'ri bo'shatilishini va "poyga holatlari" (race conditions) yoki eskirgan "closure"lar kabi potentsial muammolarning oldini olishni ta'minlaydi.
useEffect(() => {
const subscription = subscribeToChat(props.chatId);
return () => {
// Tozalash: chatId o'zgarganda yoki komponent unmount bo'lganda obunani bekor qilish
unsubscribeFromChat(subscription);
};
}, [props.chatId]);
2. Keng tarqalgan useEffect Qo'llanilish Holatlari va Shablonlari
Keling, useEffect'ning yorqin namoyon bo'ladigan amaliy ssenariylarini va har biri uchun eng yaxshi amaliyotlarni ko'rib chiqaylik.
2.1. Ma'lumotlarni Olish
Ma'lumotlarni olish, ehtimol, useEffect uchun eng keng tarqalgan qo'llanilish holatidir. Siz komponent mount bo'lganda yoki ma'lum prop/state qiymatlari o'zgarganda ma'lumotlarni olishni xohlaysiz.
Mount Paytida Asosiy Ma'lumot Olish
import React, { useEffect, useState } from 'react';
function UserProfile() {
const [userData, setUserData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchUserData = async () => {
try {
const response = await fetch('https://api.example.com/users/1');
if (!response.ok) {
throw new Error(`HTTP xatosi! status: ${response.status}`);
}
const data = await response.json();
setUserData(data);
} catch (err) {
setError(err);
} finally {
setLoading(false);
}
};
fetchUserData();
}, []); // Bo'sh massiv bu faqat mount paytida bir marta ishlashini ta'minlaydi
if (loading) return <p>Foydalanuvchi ma'lumotlari yuklanmoqda...</p>;
if (error) return <p>Xato: {error.message}</p>;
if (!userData) return <p>Foydalanuvchi ma'lumotlari topilmadi.</p>;
return (
<div>
<h2>{userData.name}</h2>
<p>Email: {userData.email}</p>
<p>Joylashuv: {userData.location}</p>
</div>
);
}
Bog'liqliklarga Asosan Ma'lumot Olish
Ko'pincha, siz oladigan ma'lumotlar foydalanuvchi IDsi, qidiruv so'rovi yoki sahifa raqami kabi dinamik qiymatga bog'liq bo'ladi. Ushbu bog'liqliklar o'zgarganda, siz ma'lumotlarni qayta olishni xohlaysiz.
import React, { useEffect, useState } from 'react';
function UserPosts({ userId }) {
const [posts, setPosts] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
if (!userId) { // userId boshida undefined bo'lishi mumkin bo'lgan holatlarni hisobga oling
setPosts([]);
setLoading(false);
return;
}
const fetchUserPosts = async () => {
setLoading(true);
setError(null);
try {
const response = await fetch(`https://api.example.com/users/${userId}/posts`);
if (!response.ok) {
throw new Error(`HTTP xatosi! status: ${response.status}`);
}
const data = await response.json();
setPosts(data);
} catch (err) {
setError(err);
} finally {
setLoading(false);
}
};
fetchUserPosts();
}, [userId]); // userId o'zgarganda qayta ma'lumot oling
if (loading) return <p>Postlar yuklanmoqda...</p>;
if (error) return <p>Xato: {error.message}</p>;
if (posts.length === 0) return <p>Ushbu foydalanuvchi uchun postlar topilmadi.</p>;
return (
<div>
<h3>Foydalanuvchi {userId} postlari</h3>
<ul>
{posts.map(post => (
<li key={post.id}>{post.title}</li>
))}
</ul>
</div>
);
}
Ma'lumotlarni Olishda "Poyga Holatlari"ni (Race Conditions) Boshqarish
Bog'liqliklar tez o'zgarganda, siz "poyga holatlari"ga duch kelishingiz mumkin, bu yerda eskiroq, sekinroq tarmoq so'rovi yangiroq, tezroq so'rovdan keyin yakunlanadi, bu esa eskirgan ma'lumotlarning ko'rsatilishiga olib keladi. Buni yumshatishning keng tarqalgan usuli bu bayroq (flag) yoki AbortController'dan foydalanishdir.
import React, { useEffect, useState } from 'react';
function ProductDetails({ productId }) {
const [product, setProduct] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const controller = new AbortController();
const signal = controller.signal;
const fetchProduct = async () => {
setLoading(true);
setError(null);
setProduct(null); // Oldingi mahsulot ma'lumotlarini tozalash
try {
const response = await fetch(`https://api.example.com/products/${productId}`, { signal });
if (!response.ok) {
throw new Error(`HTTP xatosi! status: ${response.status}`);
}
const data = await response.json();
setProduct(data);
} catch (err) {
if (err.name === 'AbortError') {
console.log('So\'rov bekor qilindi');
} else {
setError(err);
}
} finally {
setLoading(false);
}
};
fetchProduct();
return () => {
// Komponent unmount bo'lganda yoki productId o'zgarganda davom etayotgan so'rovni bekor qilish
controller.abort();
};
}, [productId]);
if (loading) return <p>Mahsulot tafsilotlari yuklanmoqda...</p>;
if (error) return <p>Xato: {error.message}</p>;
if (!product) return <p>Mahsulot topilmadi.</p>;
return (
<div>
<h2>{product.name}</h2>
<p>Narx: ${product.price}</p>
<p>Tavsif: {product.description}</p>
</div>
);
}
2.2. Hodisa Tinglovchilari va Obunalar
Hodisa tinglovchilarini (masalan, klaviatura hodisalari, oyna o'lchamini o'zgartirish) yoki tashqi obunalarni (masalan, WebSockets, chat xizmatlari) boshqarish klassik yon effektdir. Tozalash funksiyasi bu yerda xotira sızıntılarını oldini olish va hodisa ishlovchilarining kerak bo'lmaganda olib tashlanishini ta'minlash uchun juda muhimdir.
Global Hodisa Tinglovchisi
import React, { useEffect, useState } from 'react';
function WindowSizeLogger() {
const [windowSize, setWindowSize] = useState({
width: window.innerWidth,
height: window.innerHeight,
});
useEffect(() => {
const handleResize = () => {
setWindowSize({
width: window.innerWidth,
height: window.innerHeight,
});
};
window.addEventListener('resize', handleResize);
return () => {
// Komponent unmount bo'lganda hodisa tinglovchisini tozalash
window.removeEventListener('resize', handleResize);
};
}, []); // Bo'sh massiv: tinglovchini faqat mount/unmount paytida bir marta qo'shish/olib tashlash
return (
<div>
<p>Oyna Kengligi: {windowSize.width}px</p>
<p>Oyna Balandligi: {windowSize.height}px</p>
</div>
);
}
Chat Xizmatiga Obuna
import React, { useEffect, useState } from 'react';
// chatService subscribe/unsubscribe metodlarini taqdim etuvchi tashqi modul deb faraz qilamiz
import { chatService } from './chatService';
function ChatRoom({ roomId }) {
const [messages, setMessages] = useState([]);
useEffect(() => {
const handleNewMessage = (message) => {
setMessages((prevMessages) => [...prevMessages, message]);
};
const subscription = chatService.subscribe(roomId, handleNewMessage);
return () => {
chatService.unsubscribe(subscription);
};
}, [roomId]); // Agar roomId o'zgarsa, qayta obuna bo'lish
return (
<div>
<h3>Chat Xonasi: {roomId}</h3>
<div className="messages">
{messages.length === 0 ? (
<p>Hali xabarlar yo'q.</p>
) : (
messages.map((msg, index) => (
<p key={index}><strong>{msg.sender}:</strong> {msg.text}</p>
))
)}
</div>
</div>
);
}
2.3. DOM Manipulyatsiyasi
React'ning deklarativ tabiati ko'pincha to'g'ridan-to'g'ri DOM manipulyatsiyasini abstraktlashtirsa-da, ba'zida siz xom DOM bilan ishlashingiz kerak bo'ladi, ayniqsa to'g'ridan-to'g'ri DOM'ga kirishni kutadigan uchinchi tomon kutubxonalari bilan integratsiya qilganda.
Hujjat Sarlavhasini O'zgartirish
import React, { useEffect } from 'react';
function PageTitleUpdater({ title }) {
useEffect(() => {
document.title = `Mening Ilovam | ${title}`;
}, [title]); // 'title' prop o'zgarganda sarlavhani yangilash
return (
<h2>{title} Sahifasiga Xush Kelibsiz!</h2>
);
}
Uchinchi Tomon Diagramma Kutubxonasi Bilan Integratsiya (masalan, Chart.js)
import React, { useEffect, useRef } from 'react';
import Chart from 'chart.js/auto'; // Chart.js o'rnatilgan deb faraz qilinadi
function MyChartComponent({ data, labels }) {
const chartRef = useRef(null); // canvas elementini ushlab turish uchun ref
const chartInstance = useRef(null); // diagramma nusxasini ushlab turish uchun ref
useEffect(() => {
if (chartRef.current) {
// Yangi diagramma yaratishdan oldin mavjud diagramma nusxasini yo'q qilish
if (chartInstance.current) {
chartInstance.current.destroy();
}
const ctx = chartRef.current.getContext('2d');
chartInstance.current = new Chart(ctx, {
type: 'bar',
data: {
labels: labels,
datasets: [{
label: 'Sotuvlar Ma\'lumotlari',
data: data,
backgroundColor: 'rgba(75, 192, 192, 0.6)',
borderColor: 'rgba(75, 192, 192, 1)',
borderWidth: 1
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
}
});
}
return () => {
// Tozalash: unmount paytida diagramma nusxasini yo'q qilish
if (chartInstance.current) {
chartInstance.current.destroy();
}
};
}, [data, labels]); // ma'lumotlar yoki yorliqlar o'zgarsa, diagrammani qayta render qilish
return (
<div style={{ width: '600px', height: '400px' }}>
<canvas ref={chartRef}></canvas>
</div>
);
}
2.4. Taymerlar
React komponentlari ichida setTimeout yoki setInterval'dan foydalanish komponent unmount bo'lgandan keyin taymerlarning ishlashda davom etishini oldini olish uchun ehtiyotkorlik bilan boshqarishni talab qiladi, bu esa xatolarga yoki xotira sızıntılarına olib kelishi mumkin.
Oddiy Ortga Sanash Taymeri
import React, { useEffect, useState } from 'react';
function CountdownTimer({ initialSeconds }) {
const [seconds, setSeconds] = useState(initialSeconds);
useEffect(() => {
if (seconds <= 0) return; // Nolga yetganda taymerni to'xtatish
const timerId = setInterval(() => {
setSeconds(prevSeconds => prevSeconds - 1);
}, 1000);
return () => {
// Tozalash: komponent unmount bo'lganda yoki soniyalar 0 bo'lganda intervalni tozalash
clearInterval(timerId);
};
}, [seconds]); // Agar initialSeconds o'zgarsa, yangi intervalni sozlash uchun soniyalar o'zgarganda effektni qayta ishga tushirish
return (
<div>
<h3>Ortga sanash: {seconds} soniya</h3>
{seconds === 0 && <p>Vaqt tugadi!</p>}
</div>
);
}
3. Ilg'or useEffect Shablonlari va Tuzoqlar
useEffect asoslari oddiy bo'lsa-da, uni o'zlashtirish yanada nozik xatti-harakatlar va keng tarqalgan tuzoqlarni tushunishni o'z ichiga oladi.
3.1. Eskirgan "Closure"lar va Qadimgi Qiymatlar
`useEffect` (va umuman JavaScript closure'lari) bilan bog'liq keng tarqalgan muammo bu oldingi renderdagi "eskirgan" qiymatlarga kirishdir. Agar sizning effekt closure'ingiz o'zgaruvchi state yoki prop'ni qamrab olsa, lekin siz uni bog'liqliklar massiviga kiritmasangiz, effekt eski qiymatni ko'rishda davom etadi.
Ushbu muammoli misolni ko'rib chiqing:
import React, { useEffect, useState } from 'react';
function StaleClosureExample() {
const [count, setCount] = useState(0);
useEffect(() => {
// Bu effekt 2 soniyadan keyin hisobni logga chiqarmoqchi.
// Agar count shu 2 soniya ichida o'zgarsa, bu ESKI hisobni logga chiqaradi!
const timer = setTimeout(() => {
console.log('Eskirgan hisob:', count);
}, 2000);
return () => {
clearTimeout(timer);
};
}, []); // Muammo: 'count' bog'liqliklarda yo'q, shuning uchun u eskirgan
return (
<div>
<p>Hisob: {count}</p>
<button onClick={() => setCount(count + 1)}>Oshirish</button>
</div>
);
}
Buni tuzatish uchun effektingiz ichida ishlatiladigan va prop yoki state'dan keladigan barcha qiymatlar bog'liqliklar massiviga kiritilganligiga ishonch hosil qiling:
import React, { useEffect, useState } from 'react';
function FixedClosureExample() {
const [count, setCount] = useState(0);
useEffect(() => {
const timer = setTimeout(() => {
console.log('To\'g\'ri hisob:', count);
}, 2000);
return () => {
clearTimeout(timer);
};
}, [count]); // Yechim: 'count' endi bog'liqlik. Effekt count o'zgarganda qayta ishlaydi.
return (
<div>
<p>Hisob: {count}</p>
<button onClick={() => setCount(count + 1)}>Oshirish</button>
</div>
);
}
Biroq, bog'liqliklarni qo'shish ba'zan effektning juda tez-tez ishlashiga olib kelishi mumkin. Bu bizni boshqa shablonlarga olib keladi:
Holat Uchun Funksional Yangilanishlardan Foydalanish
Holatni oldingi qiymatiga qarab yangilayotganda, set- funksiyalarining funksional yangilanish shaklidan foydalaning. Bu holat o'zgaruvchisini bog'liqliklar massiviga kiritish zaruratini yo'q qiladi.
import React, { useEffect, useState } from 'react';
function AutoIncrementer() {
const [count, setCount] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setCount(prevCount => prevCount + 1); // Funksional yangilanish
}, 1000);
return () => clearInterval(interval);
}, []); // 'count' bog'liqlik emas, chunki biz funksional yangilanishdan foydalanamiz
return <p>Hisob: {count}</p>;
}
Qayta Renderga Sabab Bo'lmaydigan O'zgaruvchan Qiymatlar Uchun useRef
Ba'zan siz qayta renderlarni keltirib chiqarmaydigan, lekin effektingiz ichida mavjud bo'lgan o'zgaruvchan qiymatni saqlashingiz kerak bo'ladi. useRef buning uchun mukammal.
import React, { useEffect, useRef, useState } from 'react';
function LatestValueLogger() {
const [count, setCount] = useState(0);
const latestCountRef = useRef(count); // ref yaratish
// Ref'ning joriy qiymatini eng so'nggi hisob bilan yangilab turish
useEffect(() => {
latestCountRef.current = count;
}, [count]);
useEffect(() => {
const interval = setInterval(() => {
// Eng so'nggi hisobga ref orqali kirish, eskirgan closure'dan qochish
console.log('Eng so\'nggi hisob:', latestCountRef.current);
}, 2000);
return () => clearInterval(interval);
}, []); // Bo'sh bog'liqliklar massivi, chunki biz bu yerda 'count'ni bevosita ishlatmayapmiz
return (
<div>
<p>Hisob: {count}</p>
<button onClick={() => setCount(count + 1)}>Oshirish</button>
</div>
);
}
Barqaror Bog'liqliklar Uchun useCallback va useMemo
Funktsiya yoki ob'ekt sizning useEffect'ingizning bog'liqligi bo'lganda, agar funksiya/ob'ekt havolasi har bir renderda o'zgarsa (odatda shunday bo'ladi), bu effektning keraksiz ravishda qayta ishlashiga olib kelishi mumkin. useCallback va useMemo bu qiymatlarni memoizatsiya qilish orqali yordam beradi va barqaror havola taqdim etadi.
Muammoli misol:
import React, { useEffect, useState } from 'react';
function UserSettings() {
const [userId, setUserId] = useState(1);
const [settings, setSettings] = useState({});
const fetchSettings = async () => {
// Bu funksiya har bir renderda qayta yaratiladi
console.log('Foydalanuvchi sozlamalari olinmoqda:', userId);
const response = await fetch(`https://api.example.com/users/${userId}/settings`);
const data = await response.json();
setSettings(data);
};
useEffect(() => {
fetchSettings();
}, [fetchSettings]); // Muammo: fetchSettings har bir renderda o'zgaradi
return (
<div>
<p>Foydalanuvchi IDsi: {userId}</p>
<button onClick={() => setUserId(userId + 1)}>Keyingi Foydalanuvchi</button>
<pre>{JSON.stringify(settings, null, 2)}</pre>
</div>
);
}
useCallback bilan yechim:
import React, { useEffect, useState, useCallback } from 'react';
function UserSettingsOptimized() {
const [userId, setUserId] = useState(1);
const [settings, setSettings] = useState({});
const fetchSettings = useCallback(async () => {
console.log('Foydalanuvchi sozlamalari olinmoqda:', userId);
const response = await fetch(`https://api.example.com/users/${userId}/settings`);
const data = await response.json();
setSettings(data);
}, [userId]); // fetchSettings faqat userId o'zgarganda o'zgaradi
useEffect(() => {
fetchSettings();
}, [fetchSettings]); // Endi fetchSettings barqaror bog'liqlik
return (
<div>
<p>Foydalanuvchi IDsi: {userId}</p>
<button onClick={() => setUserId(userId + 1)}>Keyingi Foydalanuvchi</button>
<pre>{JSON.stringify(settings, null, 2)}</pre>
</div>
);
}
Xuddi shunday, ob'ektlar yoki massivlar uchun barqaror havola yaratish uchun useMemo'dan foydalaning:
import React, { useEffect, useMemo, useState } from 'react';
function ProductList({ categoryId, sortBy }) {
const [products, setProducts] = useState([]);
// Filtr/saralash mezonlari ob'ektini memoizatsiya qilish
const fetchCriteria = useMemo(() => ({
category: categoryId,
sort: sortBy,
}), [categoryId, sortBy]);
useEffect(() => {
// fetchCriteria asosida mahsulotlarni olish
console.log('Mezonlar bilan mahsulotlar olinmoqda:', fetchCriteria);
// ... API so'rovi mantig'i ...
}, [fetchCriteria]); // Effekt faqat categoryId yoki sortBy o'zgarganda ishlaydi
return (
<div>
<h3>{categoryId} Kategoriyasidagi Mahsulotlar ({sortBy} bo'yicha saralangan)</h3>
<!-- Mahsulotlar ro'yxatini render qilish -->
</div>
);
}
3.2. Cheksiz Tsikllar
Agar effekt o'zining bog'liqliklar massivida bo'lgan state o'zgaruvchisini yangilasa va bu yangilanish har doim effektni qayta ishga tushiradigan qayta renderga sabab bo'lsa, cheksiz tsikl yuzaga kelishi mumkin. Bu bog'liqliklarga ehtiyot bo'lmaganda keng tarqalgan tuzoqdir.
import React, { useEffect, useState } from 'react';
function InfiniteLoopExample() {
const [data, setData] = useState([]);
useEffect(() => {
// Bu cheksiz tsiklga olib keladi!
// setData qayta renderga sabab bo'ladi, bu esa effektni qayta ishga tushiradi, u esa yana setData'ni chaqiradi.
setData([1, 2, 3]);
}, [data]); // 'data' bog'liqlik, va biz har doim yangi massiv havolasini o'rnatyapmiz
return <p>Ma'lumotlar uzunligi: {data.length}</p>;
}
Buni tuzatish uchun effektingiz faqat haqiqatan ham kerak bo'lganda ishlashiga ishonch hosil qiling yoki funksional yangilanishlardan foydalaning. Agar siz faqat mount paytida bir marta ma'lumotlarni o'rnatmoqchi bo'lsangiz, bo'sh bog'liqliklar massividan foydalaning.
import React, { useEffect, useState } from 'react';
function CorrectDataSetup() {
const [data, setData] = useState([]);
useEffect(() => {
// Bu faqat mount paytida bir marta ishlaydi
setData([1, 2, 3]);
}, []); // Bo'sh massiv qayta ishga tushirishni oldini oladi
return <p>Ma'lumotlar uzunligi: {data.length}</p>;
}
3.3. useEffect yordamida Samaradorlikni Optimallashtirish
Vazifalarni Bir Nechta useEffect Hook'lariga Bo'lish
Barcha yon effektlarni bitta katta useEffect'ga tiqishtirish o'rniga, ularni bir nechta hook'larga bo'ling. Har bir useEffect o'z bog'liqliklar to'plamini va tozalash mantig'ini boshqarishi mumkin. Bu kodni o'qilishi oson, qo'llab-quvvatlanishi oson qiladi va ko'pincha bog'liq bo'lmagan effektlarning keraksiz qayta ishga tushirilishini oldini oladi.
import React, { useEffect, useState } from 'react';
function UserDashboard({ userId }) {
const [profile, setProfile] = useState(null);
const [activityLog, setActivityLog] = useState([]);
// Foydalanuvchi profilini olish uchun effekt (faqat userId'ga bog'liq)
useEffect(() => {
const fetchProfile = async () => {
// ... profil ma'lumotlarini olish ...
console.log('Profil olinmoqda:', userId);
const response = await fetch(`https://api.example.com/users/${userId}/profile`);
const data = await response.json();
setProfile(data);
};
fetchProfile();
}, [userId]);
// Faoliyat jurnalini olish uchun effekt (shuningdek, userId'ga bog'liq, lekin alohida vazifa)
useEffect(() => {
const fetchActivity = async () => {
// ... faoliyat ma'lumotlarini olish ...
console.log('Faoliyat olinmoqda:', userId);
const response = await fetch(`https://api.example.com/users/${userId}/activity`);
const data = await response.json();
setActivityLog(data);
};
fetchActivity();
}, [userId]);
return (
<div>
<h2>Foydalanuvchi Paneli: {userId}</h2>
<h3>Profil:</h3>
<pre>{JSON.stringify(profile, null, 2)}</pre>
<h3>Faoliyat Jurnali:</h3>
<pre>{JSON.stringify(activityLog, null, 2)}</pre>
</div>
);
}
3.4. Qayta Foydalanish Uchun Maxsus Hook'lar
O'zingizni bir nechta komponentlarda bir xil useEffect mantig'ini yozayotganingizni topsangiz, bu uni maxsus hook'ga abstraktlash mumkinligining kuchli belgisidir. Maxsus hook'lar use bilan boshlanadigan va boshqa hook'larni chaqira oladigan funksiyalardir, bu esa mantig'ingizni qayta ishlatiladigan va sinovdan o'tkazish oson qiladi.
Misol: useFetch Maxsus Hook'i
import React, { useEffect, useState } from 'react';
// Maxsus Hook: useFetch.js
function useFetch(url, dependencies = []) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const abortController = new AbortController();
const signal = abortController.signal;
const fetchData = async () => {
setLoading(true);
setError(null);
try {
const response = await fetch(url, { signal });
if (!response.ok) {
throw new Error(`HTTP xatosi! status: ${response.status}`);
}
const result = await response.json();
setData(result);
} catch (err) {
if (err.name === 'AbortError') {
console.log('So\'rov bekor qilindi');
} else {
setError(err);
}
} finally {
setLoading(false);
}
};
fetchData();
return () => {
abortController.abort();
};
}, [url, ...dependencies]); // URL yoki qo'shimcha bog'liqlik o'zgarsa qayta ishga tushirish
return { data, loading, error };
}
// Maxsus hook'dan foydalanuvchi komponent: UserDataDisplay.js
function UserDataDisplay({ userId }) {
const { data: userData, loading, error } = useFetch(
`https://api.example.com/users/${userId}`,
[userId] // userId'ni maxsus hook'ga bog'liqlik sifatida o'tkazish
);
if (loading) return <p>Foydalanuvchi ma'lumotlari yuklanmoqda...</p>;
if (error) return <p>Xato: {error.message}</p>;
if (!userData) return <p>Foydalanuvchi ma'lumotlari yo'q.</p>;
return (
<div>
<h2>{userData.name}</h2>
<p>Email: {userData.email}</p>
</div>
);
}
```
4. `useEffect`'dan qachon *foydalanmaslik* kerak
Garchi kuchli bo'lsa-da, useEffect har doim ham har bir ish uchun to'g'ri vosita emas. Undan noto'g'ri foydalanish keraksiz murakkablikka, samaradorlik muammolariga yoki tuzatish qiyin bo'lgan mantig'iga olib kelishi mumkin.
4.1. Hosilaviy Holat yoki Hisoblangan Qiymatlar Uchun
Agar sizda boshqa mavjud holat yoki prop'lardan to'g'ridan-to'g'ri hisoblanishi mumkin bo'lgan holat bo'lsa, sizga useEffect kerak emas. Uni render paytida to'g'ridan-to'g'ri hisoblang.
Yomon amaliyot:
function ProductCalculator({ price, quantity }) {
const [total, setTotal] = useState(0);
useEffect(() => {
setTotal(price * quantity); // Keraksiz effekt
}, [price, quantity]);
return <p>Jami: ${total.toFixed(2)}</p>;
}
Yaxshi amaliyot:
function ProductCalculator({ price, quantity }) {
const total = price * quantity; // To'g'ridan-to'g'ri hisoblangan
return <p>Jami: ${total.toFixed(2)}</p>;
}
Agar hisoblash qimmat bo'lsa, useMemo'ni ko'rib chiqing, lekin baribir useEffect emas.
import React, { useMemo } from 'react';
function ComplexProductCalculator({ items }) {
const memoizedTotal = useMemo(() => {
console.log('Jami qayta hisoblanmoqda...');
return items.reduce((sum, item) => sum + item.price * item.quantity, 0);
}, [items]);
return <p>Murakkab Jami: ${memoizedTotal.toFixed(2)}</p>;
}
4.2. Bolalar Komponentlarining Qayta Renderini Talab Qiladigan Prop yoki Holat O'zgarishlari Uchun
Ma'lumotlarni bolalarga uzatish va ularning qayta renderlarini ishga tushirishning asosiy usuli bu prop'lar orqali. Ota-ona komponentda state'ni yangilash uchun useEffect'dan foydalanmang, keyin bu state prop sifatida o'tkaziladi, agar to'g'ridan-to'g'ri prop yangilanishi yetarli bo'lsa.
4.3. Tozalashni Talab Etmaydigan va Faqat Vizual Effektlar Uchun
Agar sizning yon effektingiz faqat vizual bo'lsa va hech qanday tashqi tizimlar, obunalar yoki taymerlarni o'z ichiga olmasa va tozalashni talab qilmasa, sizga useEffect kerak bo'lmasligi mumkin. Tashqi holatga bog'liq bo'lmagan oddiy vizual yangilanishlar yoki animatsiyalar uchun CSS yoki to'g'ridan-to'g'ri React komponent renderi yetarli bo'lishi mumkin.
Xulosa: Ishonchli Ilovalar Uchun useEffect'ni O'zlashtirish
useEffect hook'i ishonchli va reaktiv React ilovalarini yaratishning ajralmas qismidir. U React'ning deklarativ UI va yon effektlarning imperativ tabiati o'rtasidagi bo'shliqni elegant tarzda to'ldiradi. Uning asosiy tamoyillarini ā effekt funksiyasi, bog'liqliklar massivi va muhim tozalash mexanizmini tushunish orqali, siz yon effektlaringiz qachon va qanday bajarilishini nozik nazorat qilasiz.
Biz keng qamrovli shablonlarni, keng tarqalgan ma'lumotlarni olish va hodisalarni boshqarishdan tortib, "poyga holatlari" va eskirgan "closure"lar kabi murakkab ssenariylarni hal qilishgacha ko'rib chiqdik. Shuningdek, biz effekt mantig'ini abstraktlash va qayta ishlatishda maxsus hook'larning kuchini ta'kidladik, bu amaliyot turli loyihalar va global jamoalarda kodni qo'llab-quvvatlash va o'qilishini sezilarli darajada oshiradi.
useEffect'ni o'zlashtirish uchun ushbu asosiy xulosalarni yodda tuting:
- Haqiqiy Yon Effektlarni Aniqlang:
useEffect'ni "tashqi dunyo" (API'lar, DOM, obunalar, taymerlar) bilan o'zaro ta'sirlar uchun foydalaning. - Bog'liqliklarni Puxta Boshqaring: Bog'liqliklar massivi sizning asosiy nazoratingizdir. Effektingiz qanday qiymatlarga tayanayotganini aniq belgilang, bu esa eskirgan "closure"lar va keraksiz qayta ishga tushirishlarni oldini oladi.
- Tozalashga Ustuvorlik Bering: Har doim effektingiz tozalashni talab qiladimi-yo'qmi (masalan, obunani bekor qilish, taymerlarni tozalash, so'rovlarni bekor qilish) ko'rib chiqing, bu xotira sızıntılarını oldini olish va dastur barqarorligini ta'minlaydi.
- Vazifalarni Ajrating: Bir komponent ichidagi alohida, bog'liq bo'lmagan yon effektlar uchun bir nechta
useEffecthook'laridan foydalaning. - Maxsus Hook'lardan Foydalaning: Modullik va qayta foydalanishni yaxshilash uchun murakkab yoki qayta ishlatiladigan
useEffectmantig'ini maxsus hook'larga joylashtiring. - Keng Tarqalgan Tuzoqlardan Saqlaning: Cheksiz tsikllardan ehtiyot bo'ling va oddiy hosilaviy holat yoki to'g'ridan-to'g'ri prop uzatish uchun
useEffect'dan foydalanmayotganingizga ishonch hosil qiling.
Ushbu shablonlar va eng yaxshi amaliyotlarni qo'llash orqali siz React ilovalaringizda yon effektlarni ishonch bilan boshqarishga, butun dunyodagi foydalanuvchilar uchun yuqori sifatli, samarali va kengaytiriladigan foydalanuvchi tajribalarini yaratishga yaxshi tayyor bo'lasiz. Tajriba qilishda, o'rganishda va React bilan ajoyib narsalar yaratishda davom eting!