IlmHamroh
JavaScript Full-stack/20-qism. React: UI kutubxonalar va animatsiya27/30-dars19 daqiqa
Mundarija (30)

React'da View Transitions: <ViewTransition>, addTransitionType va router integratsiyasi

Qisqacha: <ViewTransition> — React 19.3.0 da barqaror komponent. U ichidagi elementga brauzerning View Transitions API'sini ulaydi: React o'zi document.startViewTransition ni chaqiradi, nom beradi va kerakli paytda DOM'ni yangilaydi. U faqat Transition ichidagi yangilanishda ishlaydi: startTransition, useDeferredValue, Action yoki Suspense. Oddiy setState — animatsiyasiz. enter, exit, update, share — qaysi holatda qanday animatsiya, addTransitionType — yo'nalish. React Router 8 navigatsiyani o'zi startTransition ga o'raydi. Shuning uchun router'ning viewTransition prop'i bilan birga ishlatilsa, ikkita o'tish to'qnashadi — Chrome'da o'lchadik.

Bu darsda

  • <ViewTransition> brauzer API'si ustida nima qilishini va nega faqat Transition'da ishlashini tushuntirasiz.
  • enter, exit, update, share va name bilan kirish, chiqish, ro'yxat tartibi va "uchuvchi" elementni yasaysiz.
  • addTransitionType bilan "oldinga" va "orqaga" o'tishlarni farqlaysiz.
  • React Router bilan ulaysiz va ikki mexanizm to'qnashuvidan qochasiz.
  • Kanon nega <ViewTransition> ni olmaganini o'lchov bilan bilasiz.

Oldin bilishingiz kerak: View Transitions: sahifa va holatlar orasida silliq o'tish, Concurrent rendering va useTransition, Scroll, breadcrumb va sahifa o'tishlari, Motion IV.

1. Nega bu kerak?

View Transitions darsida brauzerning o'zi chizadigan o'tishni ko'rdik. document.startViewTransition(yangila) — brauzer eski holatni suratga oladi, yangila() DOM'ni o'zgartiradi, keyin ikki surat orasida animatsiya. Kutubxona yo'q, 0 KB JavaScript.

React'da bu qiyin. yangila() ichida DOM'ni darhol o'zgartirish kerak. React esa DOM'ni o'zi xohlagan paytda yangilaydi: setState dan keyin, navbat bilan. Qo'lda yozilsa, flushSync bilan React'ni "majburlash" kerak. Bu Concurrent rendering darsidagi barcha yutuqni bekor qiladi. 19-qismda router'ning viewTransition prop'i buni sahifalar uchun hal qilgan edi. Lekin sahifa ichidagi kartalar, ro'yxatlar-chi?

React 19.3 javobi — <ViewTransition> komponenti. React startViewTransition ni o'zi, o'zining commit paytida chaqiradi. Siz faqat "mana bu qism o'tishda qatnashsin" deysiz.

Hayotiy o'xshatish: fotograf. CSS darsida suratni o'zingiz olardingiz: "hamma joyida turing — chiq-chiq — endi o'zgaring — chiq-chiq". <ViewTransition> da fotograf React. U tayyor bo'lganini o'zi biladi.

Bu darsning holati boshqacha. Xaritada <ViewTransition> "eksperimental" deb yozilgan, lekin React 19.3.0 da u barqaror eksport. vazifalar kanoni uni ishlatmadi (20-qaror 7). Shuning uchun "Vazifalar qadami" o'rnida — Chrome'dagi o'lchov.

2. React 19.3.0 da bormi — tekshiramiz

Avval faktni tekshiramiz: react paketi nimani eksport qiladi? Natija oynasidagi React — 19.3.0:

jsx
import * as React from "react";

console.log("versiya:", React.version);
console.log("ViewTransition:", typeof React.ViewTransition);
console.log("addTransitionType:", typeof React.addTransitionType);
console.log(
  "unstable_ViewTransition:",
  "unstable_ViewTransition" in React,
);

export default function App() {
  return null;
}

Konsolda:

text
versiya: 19.3.0
ViewTransition: symbol
addTransitionType: function
unstable_ViewTransition: false

Ekranda:

text
(bo'sh)

ViewTransition — symbol: Fragment, Suspense, Activity kabi maxsus React turi, oddiy funksiya emas. unstable_ prefiksi yo'q — barqaror API. @types/react 19.3.0 da ham ViewTransitionProps bor va komponent @version 19.3.0 bilan belgilangan. Eski maqolalarda unstable_ViewTransition va "faqat canary/experimental" degan gaplarni ko'rasiz — ular 19.3 dan oldingi davr uchun.

3. Birinchi <ViewTransition>

3.1 Karta paydo bo'ladi

Osh kartasi: «Tarkibi» bosilsa, tarkib qatori ochiladi. Ochilish startTransition ichida:

jsx
import { ViewTransition, startTransition, useState } from "react";

const css = `
  ::view-transition-group(*) { animation-duration: 0.4s; }
  @media (prefers-reduced-motion: reduce) {
    ::view-transition-group(*), ::view-transition-old(*),
    ::view-transition-new(*) { animation: none; }
  }
`;

export default function App() {
  const [open, setOpen] = useState(false);
  function toggle() {
    startTransition(() => setOpen((o) => !o));
  }
  return (
    <div>
      <style>{css}</style>
      <button onClick={toggle}>Tarkibi</button>
      {open && (
        <ViewTransition>
          <p>Guruch, sabzi, go'sht, zira</p>
        </ViewTransition>
      )}
      <p>Osh — 35 000 so'm</p>
    </div>
  );
}

Ekranda:

text
Tarkibi
Guruch, sabzi, go'sht, zira
Osh — 35 000 so'm

<style> ichidagi CSS ekranga chiqmaydi — u faqat o'tish pseudo-elementlarini sozlaydi.

3.2 Nima bo'ldi

«Ishga tushir» dan keyin «Tarkibi» ni bir necha marta bosing: tarkib qatori yumshoq paydo bo'ladi va so'nadi. Narx qatori esa pastga sirpanadi, sakramaydi. CSS'da biz faqat davomiylikni yozdik. Qolganini React va brauzer qildi:

sequenceDiagram
  participant S as startTransition
  participant R as React
  participant B as Brauzer
  S->>R: setOpen(true) — Transition
  R->>R: render: yangi daraxt tayyor
  R->>B: startViewTransition, nomlar qo'yildi
  B->>B: eski surat
  B->>R: DOM'ni yangila
  R->>B: commit: tarkib qo'shildi
  B->>B: yangi surat, animatsiya

Asosiy farq — uchinchi qadam. React avval yangi holatni xotirada tayyorlaydi (render). DOM'ga yozishdan (commit) oldin brauzerga "suratga ol" deydi. Shunda flushSync kerak bo'lmaydi.

Tekshiruvchi (jsdom) bu yerda faqat yakuniy matnni ko'radi: unda document.startViewTransition yo'q. Bunday brauzerda React o'tishsiz, oddiy commit qiladi — xato yo'q. Bu progressive enhancement: API bo'lmasa, ilova o'tishsiz ishlayveradi.

3.3 Faqat Transition'da

Endi xuddi shu kod, faqat startTransition siz:

jsx
export default function App() {
  const [open, setOpen] = useState(false);
  return (
    <div>
      <style>{css}</style>
      <button onClick={() => setOpen((o) => !o)}>Tarkibi</button>
      {open && (
        <ViewTransition>
          <p>Guruch, sabzi, go'sht, zira</p>
        </ViewTransition>
      )}
      <p>Osh — 35 000 so'm</p>
    </div>
  );
}

Ekranda:

text
Tarkibi
Guruch, sabzi, go'sht, zira
Osh — 35 000 so'm

Ekran o'sha, lekin brauzerda bosib ko'ring — animatsiya yo'q, tarkib sakrab chiqadi. Biz Chrome 155 da document.startViewTransition ni "kuzatib" o'lchadik (alohida tajriba sahifasi, React 19.3.0, Vite build):

text
oddiy: VT chaqiruvlari jami 0
oddiy: VT chaqiruvlari jami 0
otish: VT chaqiruvlari jami 1
otish: VT chaqiruvlari jami 2

Ikki marta oddiy setState — 0 ta o'tish. Ikki marta startTransition — har biriga bitta.

Nega shunday qaror? Oddiy (shoshilinch) yangilanish — klaviatura, bosish javobi. React uni darhol ko'rsatishga va'da beradi. View Transition esa bir necha o'n millisekund kutadi: avval surat, keyin DOM. @types/react izohida aynan shunday yozilgan. Sinxron yangilanish — o'tishdan "chiqish yo'li": u darhol commit bo'lishini kafolatlaydi, View Transition esa buni qila olmaydi.

Qaysi yangilanishlar o'tish yasaydi:

Yangilanish O'tish
onClick dagi setState yo'q
startTransition(() => setState(…)) bor
useDeferredValue ning kechikkan qiymati bor
Action (<form action>, useActionState) bor
Suspense: fallback → kontent bor
flushSync yo'q

Tekshirib ko'ring: Qidiruv maydoni: har harfda setQuery(…), ro'yxat esa useDeferredValue(query) bilan filtrlanadi va har qator <ViewTransition key={id}> ichida. Harf terilganda maydon "qotib" qoladimi?

Javob

Yo'q. Maydondagi matn — oddiy shoshilinch yangilanish, u darhol chiziladi va o'tishsiz. Ro'yxat esa kechiktirilgan qiymat bilan, ya'ni Transition sifatida chiziladi — o'sha qism View Transition bilan animatsiya bo'ladi. React ikki yangilanishni ajratadi: tez javob kerak bo'lgani tez, "chiroyli" bo'lishi mumkin bo'lgani — o'tish bilan (useDeferredValue darsidagi g'oya).

4. To'rt faollashish: enter, exit, update, share

4.1 Qachon nima

<ViewTransition> o'z holatiga qarab to'rt xil "faollashadi":

Holat Qachon
enter <ViewTransition> (yoki uning ota komponenti) Transition'da qo'shildi
exit Transition'da o'chirildi
update ichidagi DOM o'zgardi yoki o'lchami o'zgardi
share bir xil name li biri o'chdi, boshqasi paydo bo'ldi

Har holat uchun prop'ga o'tish classi beriladi: <ViewTransition enter="kirish" exit="chiqish">. React uni elementning view-transition-class iga yozadi (CSS darsidagi view-transition-class ning o'zi). "none" — shu holatda o'tishni o'chirish. default — boshqa hamma holatlar uchun.

4.2 Kirish va chiqish o'z animatsiyasi bilan

jsx
import { ViewTransition, startTransition, useState } from "react";

const css = `
  @keyframes tushish { from { opacity: 0; translate: 0 -12px; } }
  @keyframes ketish { to { opacity: 0; translate: 16px 0; } }
  ::view-transition-new(.kirish) { animation: tushish 0.3s ease-out; }
  ::view-transition-old(.chiqish) { animation: ketish 0.2s ease-in; }
  @media (prefers-reduced-motion: reduce) {
    ::view-transition-group(*), ::view-transition-old(*),
    ::view-transition-new(*) { animation: none; }
  }
`;

export default function App() {
  const [open, setOpen] = useState(false);
  return (
    <div>
      <style>{css}</style>
      <button onClick={() => startTransition(() => setOpen(!open))}>
        Tarkibi
      </button>
      {open && (
        <ViewTransition enter="kirish" exit="chiqish">
          <p>Guruch, sabzi, go'sht, zira</p>
        </ViewTransition>
      )}
    </div>
  );
}

Ekranda:

text
Tarkibi
Guruch, sabzi, go'sht, zira

CSS'ni o'qiymiz:

  • ::view-transition-new(.kirish) — "kirish" class'idagi elementlarning yangi surati. Paydo bo'layotgan element faqat yangi suratga ega — u yuqoridan tushadi.
  • ::view-transition-old(.chiqish) — chiqayotganning eski surati, o'ngga siljib so'nadi.
  • Davomiylik har biriga alohida. UI animatsiya tamoyillari darsidagi qoida: chiqish kirishdan qisqaroq.

Chrome'da o'lchadik: kartani yopishda React elementga view-transition-class: chiqish qo'ydi (P:_t_3_:chiqish — teg, nom, class).

4.3 Nomlar: React o'zi beradi

View Transition'da har ishtirokchiga noyob nom kerak. CSS darsida nomni qo'lda yozganmiz (view-transition-name: osh-karta). <ViewTransition> da name bermasangiz, React o'zi beradi. Chrome'da yozib olingan nomlar: _t_0_, _t_1_, _t_2_ — uchta ro'yxat qatori, _t_3_ — karta. Nom faqat o'tish paytida qo'yiladi va keyin olib tashlanadi. Shuning uchun "takroriy nom" xatosi (CSS darsidagi eng ko'p uchraydigan xato) o'z-o'zidan yo'qoladi.

4.4 Ro'yxat tartibi — update

Har qatorni <ViewTransition key> ga o'rasak, tartib o'zgarganda har qator o'z yangi joyiga siljiydi:

jsx
import { ViewTransition, startTransition, useState } from "react";

const MENU = [
  { name: "Osh", price: 35000 },
  { name: "Lag'mon", price: 28000 },
  { name: "Manti", price: 30000 },
];

export default function App() {
  const [list, setList] = useState(MENU);
  function sortCheap() {
    startTransition(() => {
      setList([...list].sort((a, b) => a.price - b.price));
    });
  }
  return (
    <div>
      <button onClick={sortCheap}>Arzonidan</button>
      <ul>
        {list.map((d) => (
          <ViewTransition key={d.name}>
            <li>
              {d.name} — {d.price}
            </li>
          </ViewTransition>
        ))}
      </ul>
    </div>
  );
}

Ekranda:

text
Arzonidan
Lag'mon — 28000
Manti — 30000
Osh — 35000

Natija oynasida bosing: osh pastga siljiydi, lag'mon va manti yuqoriga. Bu Motion III dagi layout ning ishi edi — endi kutubxonasiz. Brauzer har qatorning eski va yangi joyini suratdan biladi.

key <ViewTransition> ning o'zida. U ro'yxatning to'g'ridan-to'g'ri bolasi, React qatorlarni u orqali taniydi.

5. name va share: element boshqa joyga uchadi

Ikki turli <ViewTransition> bir xil name olsa, biri o'chib ikkinchisi paydo bo'lganda brauzer ularni bitta element deb biladi. Ular orasida o'rin va o'lcham animatsiyasi bo'ladi. Motion'dagi layoutId ning (Motion III) View Transitions'dagi egizagi:

jsx
import { ViewTransition, startTransition, useState } from "react";

const small = { width: 80, padding: 8, border: "2px solid #1d4ed8" };
const big = { width: 260, padding: 24, border: "2px solid #1d4ed8" };

export default function App() {
  const [open, setOpen] = useState(false);
  const toggle = () => startTransition(() => setOpen(!open));
  return open ? (
    <ViewTransition name="osh-rasm" share="uchish">
      <button style={big} onClick={toggle}>
        Osh — 35 000 so'm (yopish)
      </button>
    </ViewTransition>
  ) : (
    <ViewTransition name="osh-rasm" share="uchish">
      <button style={small} onClick={toggle}>
        Osh
      </button>
    </ViewTransition>
  );
}

Ekranda:

text
Osh — 35 000 so'm (yopish)

Galereyadagi kichik rasm → katta ko'rinish, ro'yxatdagi karta → batafsil sahifa — shu naqsh. Ikki shart bor. name sahifada bir vaqtda faqat bitta ko'rinadigan <ViewTransition> da bo'lsin. Va ikkalasi bitta Transition'da almashsin. Chrome o'lchovida taom-rasm nomli umumiy guruh shunday chiqdi: ::view-transition-group(taom-rasm).

6. addTransitionType: yo'nalish

Slayderda «Keyingi» — yangi taom o'ngdan kirsin, «Oldingi» — chapdan. Animatsiya sababga bog'liq. addTransitionType("oldinga") — Transition ichida chaqiriladi va o'tishga yorliq qo'yadi. Prop'larga obyekt beriladi: tur → class.

jsx
import {
  ViewTransition,
  addTransitionType,
  startTransition,
  useState,
} from "react";

const DISHES = ["Osh", "Lag'mon", "Manti"];
const css = `
  @keyframes ongdan { from { translate: 40px 0; opacity: 0; } }
  @keyframes chapdan { from { translate: -40px 0; opacity: 0; } }
  ::view-transition-new(.ongdan) { animation: ongdan 0.3s; }
  ::view-transition-new(.chapdan) { animation: chapdan 0.3s; }
`;

export default function App() {
  const [i, setI] = useState(0);
  function go(step, type) {
    startTransition(() => {
      addTransitionType(type);
      setI((i + step + DISHES.length) % DISHES.length);
    });
  }
  return (
    <div>
      <style>{css}</style>
      <button onClick={() => go(-1, "orqaga")}>Oldingi</button>{" "}
      <button onClick={() => go(1, "oldinga")}>Keyingi</button>
      <ViewTransition
        key={DISHES[i]}
        enter={{ oldinga: "ongdan", orqaga: "chapdan" }}
        exit="none"
      >
        <h2>{DISHES[i]}</h2>
      </ViewTransition>
    </div>
  );
}

Ekranda:

text
Oldingi Keyingi
Lag'mon

key={DISHES[i]} — har taom "yangi" komponent, demak har almashinuvda enter va exit. enter={{ oldinga: "ongdan", orqaga: "chapdan" }} — tur bo'yicha class. exit="none" — chiqayotgan taom alohida animatsiya qilmasin (u ildiz crossfade'ida so'nadi).

Chrome'da yozib olindi: addTransitionType("oldinga") dan keyin brauzerning ViewTransition obyektida types: ["oldinga"], onEnter esa ikkinchi argumentda [oldinga] oldi. Ya'ni React turlarni brauzerga uzatadi. CSS darsidagi :active-view-transition-type(oldinga) CSS selektori ham ishlaydi.

6.1 Hodisalar: onEnter, onExit, onUpdate, onShare

Har holatga hodisa ham bor: onEnter={(instance, types) => …}. instance.name — o'tish nomi (_t_4_ yoki siz bergan). Funksiya qaytarilsa — tozalash. Bu hodisalar faqat haqiqiy o'tishda chaqiriladi: API yo'q brauzerda (va tekshiruvchimizdagi jsdom'da) ular jim. Shuning uchun muhim mantiqni (ma'lumot saqlash, fokus) ularga bog'lamang.

7. Router integratsiyasi

7.1 React Router 8 navigatsiyani o'zi startTransition ga o'raydi

19/#10 da <NavLink viewTransition> ni ko'rdik: router o'zi document.startViewTransition ni chaqiradi. Endi React'ning <ViewTransition> i ham bor. Ikkalasi birga nima qiladi?

React Router 8.4.0 manba kodida (RouterProvider) — useTransitions sozlamasi. Hujjat izohi: "undefined qoldirilsa, router holatining hamma yangilanishlari React.startTransition ga o'raladi". Demak <ViewTransition> sahifa almashganda o'z-o'zidan ishlaydi — viewTransition prop'isiz ham.

7.2 O'lchov: bitta, keyin uchta o'tish

Tajriba: createMemoryRouter + RouterProvider ("react-router" dan, vazifalar dagidek), ikki sahifa, har biri <ViewTransition> ichida. Avval oddiy navigatsiya, keyin viewTransition: true bilan (Chrome 155):

text
navigate (oddiy): VT 1 Statistika
navigate (viewTransition: true): VT 3 Ro'yxat
{"tur":[],"psevdo":[],"ms":345,"xato":"AbortError: Transition was skipped. New ViewTransition started"}
  • Oddiy navigatsiya — bitta o'tish. React'niki, chunki router startTransition ishlatdi.
  • viewTransition: true — yana ikkita: avval router startViewTransition ni chaqirdi. Ichida React startTransition ni ko'rib, o'zinikini boshladi. Brauzer bir vaqtda bitta o'tishga ruxsat beradi — birinchisi bekor bo'ldi: AbortError: Transition was skipped. New ViewTransition started. Tarjimasi: "o'tish o'tkazib yuborildi — yangi ViewTransition boshlandi".

Sahifa to'g'ri ochildi, konsolda ushlanmagan xato yo'q — router xatoni o'zi ushladi. Lekin bekorga bajarilgan ish va kutilmagan animatsiya bor. Qoida: bitta mexanizm tanlang. <ViewTransition> ishlatsangiz — viewTransition prop'ini olib tashlang.

7.3 Sahifa almashsa — update, enter emas

O'sha o'lchovdagi hodisalar logi:

text
"log":["update Statistika","update Ro'yxat"]

Sahifa almashdi, lekin enter/exit emas — update. Sababi React'ning moslashtirish qoidasi (State'ning saqlanishi va key): ikkala sahifa bir xil komponent, bir xil joyda. React uni "yangilandi" deb biladi va eski hamda yangi sahifa crossfade bo'ladi. Kirish/chiqish animatsiyasi kerak bo'lsa — key:

jsx
const { pathname } = useLocation();
return (
  <ViewTransition key={pathname} enter="kirish" exit="chiqish">
    <Outlet />
  </ViewTransition>
);

key bilan qayta o'lchadik — log: ["exit Ro'yxat","enter Statistika","exit Statistika","enter Ro'yxat"]. Endi har sahifa chiqadi va kiradi.

Next.js App Router ham shu komponent bilan ishlaydi. Uning hujjatida: React 19.3 bilan "sozlamasiz" — avvalgi experimental.viewTransition bayrog'i olib tashlangan. Eski maqolalarda shu bayroqni ko'rasiz. Next.js'ni keyingi qismlarda o'rganamiz — hozir bilish shart emas.

8. Harakatni kamaytirish va CSP

Harakatni kamaytirish. React prefers-reduced-motion ga qaramaydi — o'tish baribir yaratiladi. Animatsiyani CSS o'chiradi: yuqoridagi bloklardagi @media (prefers-reduced-motion: reduce) qoidasi. O'lchov (Chrome, prefers-reduced-motion: reduce emulyatsiyasi, kanon CSS'i): o'tish davomiyligi ~320–350 ms dan 19–27 ms ga tushdi — surat olish va almashtirish qoldi, harakat yo'q. Bu qoida vazifalar ning asos.css ida 19-qismdan beri bor.

CSP. vazifalar CSP'si (style-src 'self', Trusted Types) ostida 5 xil o'tish — 0 buzilish. React nomni element.style.viewTransitionName = … bilan qo'yadi (CSSOM — ruxsat). <style> tegi yaratmaydi. Motion III dagi popLayout va Radix modal rejimidan farqli — qattiq CSP bilan to'liq chiqishadi.

Brauzer mosligi. View Transitions darsidagi jadval: bir sahifa ichidagi o'tishlar — Baseline 2025-yil oktabrdan (Firefox 144 oxirgi bo'lib qo'shgan). Eski brauzerda — o'tishsiz, xatosiz.

9. Kanon nega <ViewTransition> ni olmadi — tajriba

vazifalar da ikki joyda harakat bor: sahifa almashishi va ro'yxat qatorlari. Ikkalasi <ViewTransition> ga mos keladi. Kanon qarori (20-qaror 7, QADAMLAR asosiy qaror 7): "Kanonga kirmadi: sahifa o'tishi — router viewTransition (19/#10, ishlaydi), qator animatsiyasi — Motion; ikkinchi mexanizm qo'shilmadi."

Bugungi o'lchov bu qarorni yana bir sabab bilan mustahkamlaydi:

  1. Sahifa o'tishi. vazifalar da NavLink viewTransition bor. <ViewTransition> qo'shilsa — «Router integratsiyasi» bo'limidagi to'qnashuv. Biri olib tashlanishi kerak. Ikkalasining natijasi ko'zga bir xil (crossfade, 120 ms).
  2. Qator animatsiyasi. Yangi qator startTransition siz qo'shiladi (forma — shoshilinch yangilanish). <ViewTransition> u yerda ishlamasdi. Uni Transition'ga o'tkazish — kiritish javobini kechiktirish.
  3. O'tish paytida bosish. 19/#10 dagi e2e topilmasi: o'tish paytida sahifa "surat", bosish unga yetmaydi. Ro'yxatda tez-tez bosiladigan tugmalar bor. Motion animatsiyasi esa haqiqiy DOM'da — bosish ishlaydi.

Qachon <ViewTransition> to'g'ri tanlov? Yangi loyihada, Motion hali yo'q bo'lsa. O'tishlar asosan navigatsiya, galereya va katalogda bo'lsa. Qattiq CSP kerak bo'lsa. 0 KB JavaScript — eng katta afzalligi.

10. Ko'p uchraydigan xatolar

Belgi Sabab Davosi
hech qanday animatsiya yo'q yangilanish startTransition siz startTransition / useDeferredValue
konsolda AbortError: Transition was skipped router viewTransition + <ViewTransition> bitta mexanizm
sahifa almashganda enter ishlamaydi bir xil komponent → update key={pathname}
ro'yxat qatorlari siljimaydi, hammasi crossfade <ViewTransition> ro'yxatni butunlay o'raydi har qator alohida, key bilan
name li element "uchmaydi" ikkalasi bir vaqtda ko'rinadi yoki turli Transition'da bir Transition'da almashsin
onEnter testda chaqirilmaydi jsdom'da API yo'q mantiqni hodisaga bog'lamang
eski kodda unstable_ViewTransition 19.3 dan oldingi API import { ViewTransition } from "react"

11. Mashqlar

Mashqlar kurs/mashqlar/20/27-view-transition/ da.

1-mashq (oson): o'tish bo'ladimi?

Har yangilanish <ViewTransition> ichidagi elementni o'zgartiradi. O'tish bo'ladimi? (ha yoki yo'q)

  • onClick={() => setOpen(true)} →
  • onClick={() => startTransition(() => setOpen(true))} →
  • <form action={saveAction}> dagi Action ichida state o'zgardi →
  • flushSync(() => setOpen(true)) →
Yechim
  • yo'q — oddiy shoshilinch yangilanish, React uni darhol ko'rsatadi.
  • ha — Transition.
  • ha — Action'lar Transition ichida ishlaydi (Actions).
  • yo'q — flushSync majburan sinxron commit qiladi, surat olishni kutolmaydi.

2-mashq (o'rta): filtr animatsiyasiz

«Bahor» menyusida «Faqat 30 000 gacha» katakchasi bor. Dizayner filtrlashda qolgan qatorlar silliq siljishini xohlaydi. Hozir hech narsa siljimaydi. Ikki xato bor — toping va tuzating. Natija ekrani o'zgarmasin.

Ishora: «Faqat Transition'da» va «Ro'yxat tartibi — update» bo'limlari.

jsx
import { ViewTransition, useState } from "react";

const MENU = [
  { name: "Osh", price: 35000 },
  { name: "Lag'mon", price: 28000 },
  { name: "Manti", price: 30000 },
];

export default function App() {
  const [cheap, setCheap] = useState(false);
  const list = cheap ? MENU.filter((d) => d.price <= 30000) : MENU;
  return (
    <div>
      <button onClick={() => setCheap(!cheap)}>
        Faqat 30 000 gacha
      </button>
      <ViewTransition>
        <ul>
          {list.map((d) => (
            <li key={d.name}>{d.name}</li>
          ))}
        </ul>
      </ViewTransition>
    </div>
  );
}

Ekranda:

text
Faqat 30 000 gacha
Lag'mon
Manti
Yechim
jsx
import { ViewTransition, startTransition, useState } from "react";

const MENU = [
  { name: "Osh", price: 35000 },
  { name: "Lag'mon", price: 28000 },
  { name: "Manti", price: 30000 },
];

export default function App() {
  const [cheap, setCheap] = useState(false);
  const list = cheap ? MENU.filter((d) => d.price <= 30000) : MENU;
  function toggle() {
    startTransition(() => setCheap(!cheap));
  }
  return (
    <div>
      <button onClick={toggle}>Faqat 30 000 gacha</button>
      <ul>
        {list.map((d) => (
          <ViewTransition key={d.name}>
            <li>{d.name}</li>
          </ViewTransition>
        ))}
      </ul>
    </div>
  );
}

Ekranda:

text
Faqat 30 000 gacha
Lag'mon
Manti

Birinchi xato — oddiy setCheap: Transition yo'q, o'tish yo'q. Ikkinchisi — bitta <ViewTransition> butun <ul> ni o'radi. Butun ro'yxat bitta "surat" bo'ldi va qatorlar alohida siljiy olmaydi. Har qatorga o'z <ViewTransition key> — endi osh chiqadi (exit), lag'mon va manti yangi joyiga siljiydi (update).

3-mashq (qiyin): bron qadamlari — yo'nalish bilan

Bron formasi uch qadamli: «Sana», «Odamlar», «Tasdiq». «Keyingi» — yangi qadam o'ngdan kirsin, «Orqaga» — chapdan. Talablar:

  1. Qadam nomi <h2> da, <ViewTransition key={…}> ichida.
  2. Tugmalar startTransition + addTransitionType("oldinga" | "orqaga").
  3. Birinchi qadamda «Orqaga», oxirgisida «Keyingi» — disabled.
  4. Har o'tishda konsolga: oldinga: Odamlar kabi.

Ishora: «addTransitionType: yo'nalish» bo'limidagi slayder. disabled tugmaning bosilishini o'chiradi.

Yechim
jsx
import {
  ViewTransition,
  addTransitionType,
  startTransition,
  useState,
} from "react";

const STEPS = ["Sana", "Odamlar", "Tasdiq"];

export default function App() {
  const [step, setStep] = useState(0);
  function go(delta, type) {
    const next = step + delta;
    startTransition(() => {
      addTransitionType(type);
      setStep(next);
    });
    console.log(`${type}: ${STEPS[next]}`);
  }
  return (
    <div>
      <ViewTransition
        key={STEPS[step]}
        enter={{ oldinga: "ongdan", orqaga: "chapdan" }}
        exit="none"
      >
        <h2>{STEPS[step]}</h2>
      </ViewTransition>
      <button
        disabled={step === 0}
        onClick={() => go(-1, "orqaga")}
      >
        Orqaga
      </button>{" "}
      <button
        disabled={step === STEPS.length - 1}
        onClick={() => go(1, "oldinga")}
      >
        Keyingi
      </button>
    </div>
  );
}

Konsolda:

text
oldinga: Odamlar
oldinga: Tasdiq
orqaga: Odamlar

Ekranda:

text
Odamlar
Orqaga Keyingi

CSS (ongdan, chapdan keyframes) — slayder misolidagidek, loyihaning CSS faylida. Haqiqiy formada qadam almashganda fokusni yangi <h2> ga o'tkazing (Fokus boshqaruvi): o'tish ko'zga ko'rinadi, Malika esa yangi qadam nomini eshitishi kerak.

4-mashq: Vazifalar qadami — tajriba (commit yo'q)

vazifalar ning alohida branch'ida (tajriba/view-transition) Qobiq.tsx dagi <Outlet /> ni <ViewTransition key={pathname}> ga o'rang va NavLink lardan viewTransition ni olib tashlang. Brauzerda bo'limlarni almashtiring, DevTools → Animations panelida o'tishni ko'ring. Keyin viewTransition ni qaytaring, <ViewTransition> ni qoldiring — konsolda nima chiqadi? Branch'ni o'chiring.

Yechim
  • Faqat <ViewTransition key={pathname}> — har bo'lim almashganda bitta o'tish: eski bo'lim chiqadi, yangisi kiradi.
  • Ikkalasi birga — o'tish ikki marta boshlanadi, birinchisi bekor bo'ladi (AbortError: Transition was skipped. New ViewTransition started; router uni ushlaydi, lekin DevTools'da ikki o'tish ko'rinadi).
  • Xulosa — kanon qarori: bitta mexanizm. vazifalar da router viewTransition qoladi.
  • git switch main && git branch -D tajriba/view-transition.

12. Real ishda

  • Katalog va galereyalar — kartadan batafsil sahifaga "uchuvchi" rasm (name + share), filtrlashda siljiydigan kartalar. 0 KB JavaScript — onlayn do'konlar uchun muhim.
  • Mobil uslubdagi veb-ilovalar — ekranlar orasida "oldinga/orqaga" siljish (addTransitionType). Telegram Mini App kabi ilovalarda (21-qism) native ilova hissini beradi.
  • Freymvorklar — React Router, Next.js <ViewTransition> ni qo'llab-quvvatlashga o'tmoqda. Eski loyihalarda esa router'ning o'z viewTransition prop'i — ikkalasini aralashtirmang.
  • Intervyu savollari: "<ViewTransition> qachon ishga tushadi?", "nega oddiy setState animatsiya qilmaydi?", "enter va update farqi?", "View Transition va Motion layout — qachon qaysi biri?".

Xulosa

  • <ViewTransition> — React 19.3.0 da barqaror. React startViewTransition ni o'zi, render va commit orasida chaqiradi va nomlarni o'zi beradi.
  • Faqat Transition'da ishlaydi: startTransition, useDeferredValue, Action, Suspense. Oddiy setState — 0 o'tish (Chrome o'lchovi).
  • enter, exit, update, share — view-transition-class beradi; name — umumiy element; addTransitionType — yo'nalish.
  • React Router 8 navigatsiyani startTransition ga o'raydi: <ViewTransition> o'zi ishlaydi. viewTransition prop bilan birga — ikki o'tish va AbortError. Bitta mexanizm tanlang.
  • CSP bilan to'liq mos (0 buzilish), prefers-reduced-motion — CSS bilan.

Keyingi dars: GSAP: murakkab timeline va ScrollTrigger — marketing sahifalar va murakkab ketma-ketliklar uchun eng kuchli animatsiya vositasi.

Manbalar

  • React: <ViewTransition>, addTransitionType — react.dev/reference/react/ViewTransition (React 19.3.0, 2026-10); @types/react 19.3.0 ViewTransitionProps
  • React Router 8.4.0: RouterProvider useTransitions — reactrouter.com/explanation/react-transitions; manba react-router/dist/production/lib/components.js
  • MDN: View Transition API, ViewTransition.types — developer.mozilla.org/docs/Web/API/View_Transition_API
  • Next.js: View Transitions guide — nextjs.org/docs/app/guides/view-transitions ("works with no configuration", React 19.3)
  • Chrome for Developers: View transition classes va types — developer.chrome.com/docs/web-platform/view-transitions
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
React'da View Transitions: <ViewTransition>, addTransitionType va router integratsiyasi — IlmHamroh