useLayoutEffect — useEffect dan farqi, qachon kerak

~10 daq · React · Hooks — Ilg'or

Muammo: miltillash (flicker)

Ba'zan komponent ekranda paydo bo'lganda bir lahza noto'g'ri joyda ko'rinadi, keyin to'g'ri joyga "sakraydi". Bu — miltillash. Foydalanuvchi buni sezadi.

Misol: tooltip yaratyapsiz. U bosgan elementning yonida paydo bo'lishi kerak. Lekin ekran chetiga yaqin bo'lsa — chapga siljishi kerak. Buning uchun tooltip ning o'lchamini o'lchab, pozitsiyasini hisoblash kerak.

useEffect bilan:

1. Tooltip ekranda paydo bo'ldi (noto'g'ri joyda)
2. Foydalanuvchi bir lahza noto'g'ri joyni ko'rdi  ← miltillash
3. useEffect ishladi — pozitsiya hisoblandi
4. Tooltip to'g'ri joyga ko'chdi

useLayoutEffect bilan:

1. DOM yangilandi (tooltip hali ko'rinmaydi)
2. useLayoutEffect ishladi — pozitsiya hisoblandi
3. Tooltip to'g'ridan-to'g'ri to'g'ri joyda paydo bo'ldi  ← miltillash yo'q

Farq: qachon ishlaydi?

Render jarayoni:

  JSX hisoblandi
       │
       ▼
  DOM yangilandi
       │
       ├── useLayoutEffect ishlaydi  ← brauzer chizishdan OLDIN
       │
       ▼
  Brauzer ekranda chizadi  ← foydalanuvchi ko'radi
       │
       ▼
  useEffect ishlaydi

useLayoutEffect — DOM tayyor, lekin foydalanuvchi hali ko'rmagan paytda ishlaydi. Shu paytda DOM ni o'zgartirsangiz — foydalanuvchi faqat yakuniy natijani ko'radi.


Amaliy misol — tooltip

function Tooltip({ matn, children }) {
  const tooltipRef = useRef(null);
  const [chap, setChap] = useState(0);

  useLayoutEffect(() => {
    const tooltip = tooltipRef.current;
    const rect = tooltip.getBoundingClientRect();

    // Ekranning o'ng chetidan chiqib ketayaptimi?
    if (rect.right > window.innerWidth) {
      // Chapga siljit
      setChap(window.innerWidth - rect.width - 8);
    }
  }, []);

  return (
    <div style={{ position: 'relative', display: 'inline-block' }}>
      {children}
      <div
        ref={tooltipRef}
        style={{
          position: 'absolute',
          top: '100%',
          left: chap,
          background: '#333',
          color: '#fff',
          padding: '4px 8px',
          borderRadius: '4px',
          whiteSpace: 'nowrap',
        }}
      >
        {matn}
      </div>
    </div>
  );
}

Bu yerda useEffect ishlatilsa — tooltip avval o'ng tomonda paydo bo'lib, keyin chapga sakrardi. useLayoutEffect bilan — to'g'ridan-to'g'ri to'g'ri joyda paydo bo'ladi.


Qoida

useEffect       → 99% holat uchun
useLayoutEffect → DOM o'lchamini o'qib, darhol o'zgartirish kerak bo'lganda

⚠️ useLayoutEffect sinxron ishlaydi — brauzer chizishni kutadi. Ichida og'ir ish qilsangiz — sahifa "qotib" qoladi. Faqat DOM o'lchash va pozitsiya hisoblash uchun ishlating.


Xulosa

useEffect:       DOM → brauzer chizdi → effect ishladi
useLayoutEffect: DOM → effect ishladi → brauzer chizdi

Miltillash ko'rinmasa — useEffect ishlating. Tooltip, dropdown, popover kabi elementlar noto'g'ri joyda paydo bo'lib sakrasa — useLayoutEffect.


Keyingi dars

23-dars: useId — unique ID yaratish, accessibility uchun