12-bo‘lim
useRef
DOM elementiga murojaat, chizishlar orasida qiymat saqlash, ref va holat farqi hamda React 19 da ref prop sifatida.
Ushbu bo‘lim mundarijasi
useRef ikki butunlay boshqa vazifada ishlatiladi:
- DOM elementiga murojaat qilish;
- Chizishlar orasida qiymat saqlash - qayta chizishsiz.
DOM elementiga murojaat #
import { useRef } from "react";
import { chiz, bos } from "./dom-muhit.mjs";
function Fokus() {
const maydon = useRef(null);
function fokusla() {
maydon.current.focus();
maydon.current.value = "dastur yozdi";
}
return (
<div>
<input ref={maydon} />
<button onClick={fokusla}>Fokus berish</button>
</div>
);
}
await chiz(<Fokus />);
const kirish = document.querySelector("input");
console.log("boshida:", kirish.value || "(bo'sh)");
console.log("fokusdami:", document.activeElement === kirish);
await bos("button");
console.log("keyin:", kirish.value);
console.log("fokusdami:", document.activeElement === kirish);
boshida: (bo'sh)
fokusdami: false
keyin: dastur yozdi
fokusdami: true
ref={maydon} React ga "bu elementni maydon.current ga qo'y"
deydi.
Element chizilgandan keyin maydon.current haqiqiy DOM
tugunini saqlaydi.
useRef(null) boshlang'ich qiymat bilan yaratiladi va element
chizilgunicha current null bo'lib qoladi.
Shuning uchun komponent tanasida unga murojaat qilib bo'lmaydi:
function Yomon() {
const maydon = useRef(null);
maydon.current.focus(); // XATO: null
return <input ref={maydon} />;
}
DOM chizilgandan keyin ish qilish kerak bo'lsa, useEffect
ishlating - u chizishdan keyin chaqiriladi (10-bo'lim).
Hodisa ishlovchisida esa muammo yo'q: u faqat foydalanuvchi harakatidan keyin chaqiriladi va element allaqachon mavjud.
Qiymat saqlash #
import { useState, useRef } from "react";
import { chiz, bos, matn } from "./dom-muhit.mjs";
function Taqqoslash() {
const [holat, holatniOzgartir] = useState(0);
const oddiy = useRef(0);
const chizishlar = useRef(0);
chizishlar.current += 1;
return (
<div>
<p id="natija">
holat: {holat}, ref: {oddiy.current},
chizishlar: {chizishlar.current}
</p>
<button id="holat" onClick={() => holatniOzgartir(holat + 1)}>
Holatni oshirish
</button>
<button id="ref" onClick={() => { oddiy.current += 1; }}>
Ref ni oshirish
</button>
</div>
);
}
await chiz(<Taqqoslash />);
console.log(matn("#natija").replace(/\s+/g, " ").trim());
await bos("#ref");
await bos("#ref");
console.log("ref ikki marta bosildi:");
console.log(matn("#natija").replace(/\s+/g, " ").trim());
await bos("#holat");
console.log("endi holat bosildi:");
console.log(matn("#natija").replace(/\s+/g, " ").trim());
holat: 0, ref: 0, chizishlar: 1
ref ikki marta bosildi:
holat: 0, ref: 0, chizishlar: 1
endi holat bosildi:
holat: 1, ref: 2, chizishlar: 2
Natija juda ma'lumotli:
refni ikki marta oshirdik, lekin ekran o'zgarmadi.- Keyin holatni oshirdik - va shundagina
ref: 2ko'rindi.
Bu asosiy farq:
useState | useRef | |
|---|---|---|
| O'zgarganda qayta chizadi | Ha | Yo'q |
| Chizishlar orasida saqlanadi | Ha | Ha |
| O'zgartirish | ozgartir(...) | ref.current = ... |
| Chizishda o'qish | Xavfsiz | Tavsiya etilmaydi |
Oddiy qoida: qiymat ekranda ko'rinishi kerak bo'lsa - holat. Faqat kod uchun kerak bo'lsa - ref.
Yuqorida chizishlar.current ekranga chiqarildi - bu aslida
qoidaning buzilishi va faqat namoyish uchun qilingan. Haqiqiy
kodda ref ni chizish paytida o'qimang: uning qiymati eskirgan
bo'lishi mumkin.
Taymer identifikatori #
import { useState, useRef } from "react";
import { chiz, bos, kut, matn } from "./dom-muhit.mjs";
function Sanoq() {
const [soni, ozgartir] = useState(0);
const taymer = useRef(null);
function boshla() {
if (taymer.current !== null) return;
taymer.current = setInterval(() => ozgartir((o) => o + 1), 20);
}
function toxtat() {
clearInterval(taymer.current);
taymer.current = null;
}
return (
<div>
<p id="soni">Soni: {soni}</p>
<button id="boshla" onClick={boshla}>Boshlash</button>
<button id="toxtat" onClick={toxtat}>To'xtatish</button>
</div>
);
}
await chiz(<Sanoq />);
console.log(matn("#soni"));
await bos("#boshla");
await kut(100);
await bos("#toxtat");
const toxtaganda = Number(matn("#soni").split(": ")[1]);
console.log("to'xtatilgandan keyin nol dan katta:", toxtaganda > 0);
await kut(100);
const keyinroq = Number(matn("#soni").split(": ")[1]);
console.log("to'xtagandan keyin o'zgarmadi:", keyinroq === toxtaganda);
Soni: 0
to'xtatilgandan keyin nol dan katta: true
to'xtagandan keyin o'zgarmadi: true
Taymer identifikatori uchun ref ideal: u saqlanishi kerak,
lekin ekranda ko'rinmaydi.
Aniq son chiqarilmadi - u vaqtga bog'liq bo'lardi.
Oldingi qiymatni eslash #
import { useState, useRef, useEffect } from "react";
import { chiz, bos, matn } from "./dom-muhit.mjs";
function OldingiBilan() {
const [qiymat, ozgartir] = useState(10);
const oldingi = useRef(null);
useEffect(() => {
oldingi.current = qiymat;
}, [qiymat]);
return (
<div>
<p id="natija">
hozir: {qiymat}, oldin: {oldingi.current ?? "yo'q"}
</p>
<button onClick={() => ozgartir(qiymat + 5)}>Oshirish</button>
</div>
);
}
await chiz(<OldingiBilan />);
console.log(matn("#natija").replace(/\s+/g, " ").trim());
await bos("button");
console.log(matn("#natija").replace(/\s+/g, " ").trim());
await bos("button");
console.log(matn("#natija").replace(/\s+/g, " ").trim());
hozir: 10, oldin: yo'q
hozir: 15, oldin: 10
hozir: 20, oldin: 15
Effekt chizishdan keyin ishlagani uchun (10-bo'lim),
oldingi.current chizish paytida hali eski qiymatni saqlab
turadi.
Bu naqsh "oldingi qiymat" kerak bo'lganda ishlatiladi - masalan, animatsiya yo'nalishini aniqlashda.
React 19: ref oddiy prop #
import { useRef } from "react";
import { chiz, bos } from "./dom-muhit.mjs";
function OzMaydonim({ ref, ...qolgani }) {
return <input ref={ref} className="ozim" {...qolgani} />;
}
function Sahifa() {
const maydon = useRef(null);
return (
<div>
<OzMaydonim ref={maydon} placeholder="yozing" />
<button onClick={() => { maydon.current.value = "ishladi"; }}>
To'ldirish
</button>
</div>
);
}
await chiz(<Sahifa />);
console.log("sinf:", document.querySelector("input").className);
await bos("button");
console.log("qiymat:", document.querySelector("input").value);
sinf: ozim
qiymat: ishladi
React 18 va undan oldin ref ni komponentga oddiy prop sifatida
berib bo'lmasdi - u maxsus hisoblanardi. Buning uchun forwardRef
o'rami yozilardi:
const OzMaydonim = forwardRef((props, ref) => (
<input ref={ref} {...props} />
));
React 19 da ref oddiy prop ga aylandi: uni boshqa props
kabi qabul qilish va uzatish mumkin.
forwardRef hali ishlaydi, lekin yangi kodda kerak emas. Eski
qo'llanmalarda uni ko'p uchratasiz.
Ref ni qachon ishlatmaslik kerak #
import { useRef } from "react";
import { chiz, bos } from "./dom-muhit.mjs";
function Yomon() {
const soni = useRef(0);
return (
<button onClick={() => { soni.current += 1; }}>
Soni: {soni.current}
</button>
);
}
await chiz(<Yomon />);
console.log("boshida:", document.querySelector("button").textContent);
await bos("button");
await bos("button");
console.log("ikki bosishdan keyin:",
document.querySelector("button").textContent);
boshida: Soni: 0
ikki bosishdan keyin: Soni: 0
soni.current ikki marta oshdi, lekin ekran qotib qoldi -
chunki ref o'zgarishi qayta chizishga sabab bo'lmaydi.
Bu "nega mening sonim yangilanmayapti?" degan savolning eng keng tarqalgan sababi.
Tekshiruv oddiy: bu qiymat ekranda ko'rinadimi?
- Ha →
useState. - Yo'q →
useRef.
Ref uchun to'g'ri holatlar: DOM elementi, taymer identifikatori, oldingi qiymat, tashqi kutubxona obyekti, "birinchi chizishmi" degan bayroq.
refbilan maydonga fokus bering.- Komponent tanasida
ref.currentga murojaat qilib, xatoni ko'ring. - Ref va holatni yonma-yon oshirib, farqni ko'ring.
- Chizishlar sonini ref bilan sanang.
- Taymer identifikatorini ref da saqlang.
- Taymerni to'xtatib, hisob o'sishdan to'xtaganini tekshiring.
- Oldingi qiymatni effekt bilan eslang.
refni o'z komponentingizga prop sifatida uzating.forwardRefbilan eski shaklni yozib ko'ring.- Ekranda ko'rinadigan qiymatni ref da saqlab, oqibatini ko'ring.
Xulosa #
useRefikki vazifada: DOM elementi va qayta chizishsiz saqlanadigan qiymat.currentelement chizilgunichanullbo'ladi.- Ref o'zgarishi qayta chizishga sabab bo'lmaydi.
- Ekranda ko'rinadigan qiymat - holat; faqat kod uchun keragi - ref.
- Chizish paytida
ref.currentni o'qimang - u eskirgan bo'lishi mumkin. - React 19 da
refoddiy prop;forwardRefkerak emas.
Keyingi bo'limda kontekstni o'rganamiz.
O‘qish tarixini saqlamoqchimisiz?
Tizimga kirsangiz, tugatgan bo‘limlaringiz saqlanadi va qoldirgan joyingizdan davom etasiz.
Xatolik topdingizmi?
Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.