useRef — re-render bo'lmasdan qiymat saqlash, useState farqi

~15 daq · React · Hooks — Asosiy

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 → useState Faqat 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:

  1. DOM elementga murojaat — ref={...} bilan
  2. 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