12-bo‘lim

useRef

DOM elementiga murojaat, chizishlar orasida qiymat saqlash, ref va holat farqi hamda React 19 da ref prop sifatida.

🕑 9 daqiqa o‘qish 📄 543 so‘z 👁 0 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. DOM elementiga murojaat
  2. Qiymat saqlash
  3. Taymer identifikatori
  4. Oldingi qiymatni eslash
  5. React 19: ref oddiy prop
  6. Ref ni qachon ishlatmaslik kerak
  7. Xulosa

useRef ikki butunlay boshqa vazifada ishlatiladi:

  1. DOM elementiga murojaat qilish;
  2. Chizishlar orasida qiymat saqlash - qayta chizishsiz.

DOM elementiga murojaat #

JSX
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);
Natija
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.

Boshida current null bo'ladi

useRef(null) boshlang'ich qiymat bilan yaratiladi va element chizilgunicha current null bo'lib qoladi.

Shuning uchun komponent tanasida unga murojaat qilib bo'lmaydi:

JSX
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 #

JSX
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());
Natija
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:

  • ref ni ikki marta oshirdik, lekin ekran o'zgarmadi.
  • Keyin holatni oshirdik - va shundagina ref: 2 ko'rindi.
ref o'zgarishi qayta chizishga sabab bo'lmaydi

Bu asosiy farq:

useStateuseRef
O'zgarganda qayta chizadiHaYo'q
Chizishlar orasida saqlanadiHaHa
O'zgartirishozgartir(...)ref.current = ...
Chizishda o'qishXavfsizTavsiya 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 #

JSX
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);
Natija
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 #

JSX
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());
Natija
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 #

JSX
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);
Natija
sinf: ozim
qiymat: ishladi
forwardRef endi kerak emas

React 18 va undan oldin ref ni komponentga oddiy prop sifatida berib bo'lmasdi - u maxsus hisoblanardi. Buning uchun forwardRef o'rami yozilardi:

JSX
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 #

JSX
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);
Natija
boshida: Soni: 0
ikki bosishdan keyin: Soni: 0
Ekranda ko'rinadigan qiymat holatda bo'lsin

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.

Amaliy topshiriq
  1. ref bilan maydonga fokus bering.
  2. Komponent tanasida ref.current ga murojaat qilib, xatoni ko'ring.
  3. Ref va holatni yonma-yon oshirib, farqni ko'ring.
  4. Chizishlar sonini ref bilan sanang.
  5. Taymer identifikatorini ref da saqlang.
  6. Taymerni to'xtatib, hisob o'sishdan to'xtaganini tekshiring.
  7. Oldingi qiymatni effekt bilan eslang.
  8. ref ni o'z komponentingizga prop sifatida uzating.
  9. forwardRef bilan eski shaklni yozib ko'ring.
  10. Ekranda ko'rinadigan qiymatni ref da saqlab, oqibatini ko'ring.

Xulosa #

  • useRef ikki vazifada: DOM elementi va qayta chizishsiz saqlanadigan qiymat.
  • current element chizilgunicha null bo'ladi.
  • Ref o'zgarishi qayta chizishga sabab bo'lmaydi.
  • Ekranda ko'rinadigan qiymat - holat; faqat kod uchun keragi - ref.
  • Chizish paytida ref.current ni o'qimang - u eskirgan bo'lishi mumkin.
  • React 19 da ref oddiy prop; forwardRef kerak emas.

Keyingi bo'limda kontekstni o'rganamiz.

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.