useRef — re-render bo'lmasdan qiymat saqlash, useState farqi
useRef ning ikkinchi ishi
useRef faqat DOM uchun emas. U re-render qilmasdan qiymat saqlash uchun ham ishlatiladi.
Farqni tushunish uchun:
useState:
qiymat o'zgardi → komponent qayta chiziladi → ekran yangilandi
useRef:
qiymat o'zgardi → komponent qayta chizilmaydi → ekran o'zgarmadi
Qachon bu kerak? Qiymatni saqlash kerak, lekin u o'zgarganda ekran yangilanmasligi kerak bo'lganda.
Amaliy misollar
Timer ID saqlash
function Taymer() {
const [vaqt, setVaqt] = useState(0);
const intervalRef = useRef(null); // timer ID saqlanadi
function boshlash() {
intervalRef.current = setInterval(() => {
setVaqt(prev => prev + 1);
}, 1000);
}
function toxtatish() {
clearInterval(intervalRef.current);
}
return (
<div>
<p>{vaqt} soniya</p>
<button onClick={boshlash}>Boshlash</button>
<button onClick={toxtatish}>To'xtatish</button>
</div>
);
}
intervalRef ni useState bilan saqlasak — har o'zgarishda re-render bo'lardi. Lekin timer ID ekranda ko'rsatilmaydi, faqat clearInterval uchun kerak. useRef to'g'ri tanlov.
Oldingi qiymatni saqlash
function Komponent({ qiymat }) {
const oldingiRef = useRef(null);
useEffect(() => {
oldingiRef.current = qiymat; // render keyin yangilanadi
});
const oldingi = oldingiRef.current;
return (
<p>
Hozir: {qiymat} | Oldin: {oldingi}
</p>
);
}
Birinchi render: qiymat=5, oldingi=null
Ikkinchi render: qiymat=10, oldingi=5
Uchinchi render: qiymat=15, oldingi=10
So'rov yuborilganmi tekshirish
function Forma() {
const [ism, setIsm] = useState('');
const yuborildiRef = useRef(false);
function yuborish() {
if (yuborildiRef.current) return; // ikki marta yuborishni oldini olish
yuborildiRef.current = true;
fetch('/api/yuborish', {
method: 'POST',
body: JSON.stringify({ ism }),
});
}
return (
<div>
<input value={ism} onChange={e => setIsm(e.target.value)} />
<button onClick={yuborish}>Yuborish</button>
</div>
);
}
useState vs useRef — qachon qaysi?
┌─────────────────────┬──────────────────────┬──────────────────────┐
│ │ useState │ useRef │
├─────────────────────┼──────────────────────┼──────────────────────┤
│ O'zgarganda re-render│ ✅ Ha │ ❌ Yo'q │
│ Ekranda ko'rsatiladi│ ✅ Ha │ ❌ Yo'q │
│ Render orasida saqlanadi│ ✅ Ha │ ✅ Ha │
├─────────────────────┼──────────────────────┼──────────────────────┤
│ Ishlatish holati │ Ekranda ko'rinadigan │ Timer ID, oldingi │
│ │ ma'lumotlar │ qiymat, DOM ref │
└─────────────────────┴──────────────────────┴──────────────────────┘
Oddiy qoida:
Ekranda ko'rsatilishi kerak →
useStateFaqat kod ichida kerak, ekranda emas →useRef
Tez-tez uchraydigan xato
useRef ni useState o'rniga ishlatish:
function Hisoblagich() {
const sonRef = useRef(0);
return (
<div>
<p>{sonRef.current}</p> {/* ❌ o'zgarganda yangilanmaydi */}
<button onClick={() => sonRef.current++}>+1</button>
</div>
);
}
Tugma bosiladi, sonRef.current o'zgaradi — lekin ekran yangilanmaydi. Ekranda ko'rsatish kerak bo'lsa — useState ishlatiladi.
Xulosa
useRef ikki ish qiladi:
- DOM elementga murojaat —
ref={...}bilan - Re-render bo'lmasdan qiymat saqlash — timer ID, oldingi qiymat, flag lar uchun
Ekranda ko'rsatiladi?
Ha → useState
Yo'q → useRef
Keyingi dars
15-dars: useMemo — qimmat hisoblashlarni keshlash, qachon kerak