<ViewTransition> - This feature is available in the latest Canary version of React

Canary

<ViewTransition /> API தற்போது React-ன் Canary மற்றும் Experimental channel-களில் மட்டுமே கிடைக்கிறது.

React-ன் release channel-கள் பற்றி இங்கே மேலும் அறிக.

<ViewTransition> Transitions மற்றும் Suspense உடன் component tree ஒன்றை animate செய்ய அனுமதிக்கிறது.

import {ViewTransition} from 'react';

<ViewTransition>
<div>...</div>
</ViewTransition>

Reference

<ViewTransition>

ஒரு component tree-ஐ animate செய்ய அதை <ViewTransition>-இல் wrap செய்யுங்கள்:

<ViewTransition>
<Page />
</ViewTransition>

மேலும் உதாரணங்களை கீழே பார்க்கவும்.

Deep Dive

<ViewTransition> எப்படி வேலை செய்கிறது?

உள்ளே, <ViewTransition> component-க்குள் nested ஆன மிக அருகிலுள்ள DOM node-ன் inline style-களுக்கு React view-transition-name-ஐப் பயன்படுத்துகிறது. <ViewTransition><div /><div /></ViewTransition> போன்ற பல sibling DOM node-கள் இருந்தால், ஒவ்வொன்றும் unique ஆக இருக்க React பெயருக்கு suffix சேர்க்கிறது; ஆனால் கருத்து ரீதியாக அவை அதே ஒன்றின் பகுதிகளாகும். React இவற்றை முன்கூட்டியே apply செய்யாது; அந்த boundary animation-இல் பங்கேற்க வேண்டிய நேரத்தில் மட்டுமே apply செய்யும்.

React பின்னணியில் தானாகவே startViewTransition-ஐ call செய்கிறது; எனவே அதை நீங்கள் நீங்களே ஒருபோதும் செய்யக்கூடாது. உண்மையில், page-இல் வேறு ஏதாவது ViewTransition ஓடிக்கொண்டிருந்தால் React அதை interrupt செய்யும். எனவே இவற்றை coordinate செய்ய React-ஐயே பயன்படுத்துவது பரிந்துரைக்கப்படுகிறது. முன்பு ViewTransition-களை trigger செய்ய வேறு வழிகளைப் பயன்படுத்தியிருந்தால், built-in வழிக்கு migrate செய்ய பரிந்துரைக்கிறோம்.

மற்ற React ViewTransition-கள் ஏற்கனவே ஓடிக்கொண்டிருந்தால், அடுத்ததைத் தொடங்கும் முன் அவை முடியும் வரை React காத்திருக்கும். ஆனால் முக்கியமாக, முதல் animation ஓடிக்கொண்டிருக்கும்போது பல update-கள் நடந்தால், அவை அனைத்தும் ஒன்றாக batch செய்யப்படும். நீங்கள் A->B-ஐத் தொடங்கினால், நடுவில் C-க்கும் பிறகு D-க்கும் செல்ல update கிடைத்தால், முதல் A->B animation முடிந்ததும் அடுத்தது B->D-ஐ animate செய்யும்.

startViewTransition-க்கு முன் getSnapshotBeforeUpdate lifecycle call செய்யப்படும்; அதே நேரத்தில் சில view-transition-name update ஆகும்.

பின்னர் React startViewTransition-ஐ call செய்கிறது. updateCallback-க்குள் React:

  • DOM-க்கு அதன் mutation-களை apply செய்து useInsertionEffect-ஐ invoke செய்யும்.
  • font-கள் load ஆக காத்திருக்கும்.
  • componentDidMount, componentDidUpdate, useLayoutEffect மற்றும் ref-களை call செய்யும்.
  • pending Navigation ஏதேனும் முடியும் வரை காத்திருக்கும்.
  • பிறகு எந்த boundary-கள் animate ஆக வேண்டும் என்பதைப் பார்க்க layout-இல் உள்ள மாற்றங்களை React measure செய்யும்.

startViewTransition-ன் ready Promise resolve ஆன பிறகு, React view-transition-name-ஐ revert செய்யும். பின்னர் animations மீது manual programmatic control வழங்க onEnter, onExit, onUpdate, மற்றும் onShare callback-களை React invoke செய்யும். built-in default animation-கள் ஏற்கனவே compute செய்யப்பட்ட பிறகு இது நடக்கும்.

இந்த sequence-ன் நடுவில் flushSync நடந்தால், synchronously முடிக்க முடிய வேண்டும் என்பதையே இது சார்ந்திருப்பதால் React Transition-ஐ skip செய்யும்.

startViewTransition-ன் finished Promise resolve ஆன பிறகு, React useEffect-ஐ invoke செய்யும். இது அவை animation performance-இல் குறுக்கிடுவதைத் தடுக்கிறது. ஆனால் இது ஒரு guarantee அல்ல; animation ஓடிக்கொண்டிருக்கும்போது இன்னொரு setState நடந்தால், sequential guarantee-களைப் பாதுகாக்க useEffect-ஐ முன்னதாகவே invoke செய்ய வேண்டியிருக்கும்.

Props

  • optional name: string அல்லது object. shared element transition-களுக்கு பயன்படுத்தப்படும் View Transition-ன் பெயர். இது வழங்கப்படாவிட்டால், எதிர்பாராத animation-களைத் தடுக்க ஒவ்வொரு View Transition-க்கும் React unique பெயரைப் பயன்படுத்தும்.
  • View Transition Class props.
  • View Transition Event props.

எச்சரிக்கைகள்

  • name-ஐ shared element transition-களுக்கு மட்டும் பயன்படுத்துங்கள். மற்ற எல்லா animation-களுக்கும், எதிர்பாராத animation-களைத் தடுக்க React தானாகவே unique பெயரை உருவாக்கும்.
  • இயல்பாக, setState உடனடியாக update ஆகும்; அது <ViewTransition>-ஐ activate செய்யாது. Transition, <Suspense>, அல்லது useDeferredValue-இல் wrap செய்யப்பட்ட update-கள் மட்டுமே ViewTransition-ஐ activate செய்யும்.
  • <ViewTransition> நகர்த்தவும் scale செய்யவும் cross-fade செய்யவும் முடியும் image ஒன்றை உருவாக்குகிறது. React Native அல்லது Motion-இல் நீங்கள் பார்த்திருக்கக்கூடிய Layout Animation-களுக்கு மாறாக, இதன் உள்ளே இருக்கும் ஒவ்வொரு தனிப்பட்ட Element-மும் அதன் position-ஐ animate செய்யாது. ஒவ்வொரு தனிப்பட்ட துண்டையும் animate செய்வதைவிட, இது மேம்பட்ட performance-க்கும் தொடர்ச்சியான, smooth animation உணர்வுக்கும் வழிவகுக்கலாம். ஆனால் தனியே நகர வேண்டும் என எதிர்பார்க்கப்படும் விஷயங்களில் continuity இழக்கலாம். எனவே அதன் விளைவாக கூடுதல் <ViewTransition> boundary-களை கைமுறையாகச் சேர்க்க வேண்டியிருக்கும்.
  • தற்போது, <ViewTransition> DOM-இல் மட்டுமே வேலை செய்கிறது. React Native மற்றும் பிற platform-களுக்கான support-ஐச் சேர்க்க நாங்கள் பணிபுரிகிறோம்.

Animation trigger-கள்

எந்த வகை View Transition animation-ஐ trigger செய்ய வேண்டும் என்பதை React தானாக தீர்மானிக்கும்:

  • enter: இந்த Transition-இல் insert செய்யப்படும் முதல் component ViewTransition ஆக இருந்தால், இது activate ஆகும்.
  • exit: இந்த Transition-இல் delete செய்யப்படும் முதல் component ViewTransition ஆக இருந்தால், இது activate ஆகும்.
  • update: React செய்யும் DOM mutation ஏதேனும் ViewTransition-க்குள் இருந்தால் (prop மாறுவது போன்றது), அல்லது immediate sibling காரணமாக ViewTransition boundary-யே size அல்லது position மாறினால். nested ViewTransition இருந்தால் mutation அவற்றுக்கு apply ஆகும்; parent-க்கு அல்ல.
  • share: named ViewTransition ஒன்று deleted subtree-க்குள் இருந்து, அதே பெயருள்ள மற்றொரு named ViewTransition அதே Transition-இல் inserted subtree-ன் பகுதியாக இருந்தால், அவை Shared Element Transition உருவாக்கும்; அது deleted ஒன்றிலிருந்து inserted ஒன்றுக்குச் animate செய்கிறது.

இயல்பாக, <ViewTransition> smooth cross-fade உடன் animate ஆகும் (browser-ன் default view transition).

ஒவ்வொரு வகை trigger-க்கும் <ViewTransition> component-க்கு View Transition Class வழங்கி animation-ஐ customize செய்யலாம் (Styling View Transitions பார்க்கவும்), அல்லது ViewTransition Event-களை பயன்படுத்தி Web Animations API மூலம் JavaScript-இல் animation-ஐ control செய்யலாம்.

Note

எப்போதும் prefers-reduced-motion-ஐச் சரிபார்க்கவும்

பல பயனர்கள் page-இல் animation-கள் இல்லாமலிருக்க விரும்பலாம். இந்தச் சூழலில் React தானாக animation-களை disable செய்யாது.

பயனர் விருப்பத்தின் அடிப்படையில் animation-களை disable செய்ய அல்லது குறைக்க @media (prefers-reduced-motion) media query-ஐ எப்போதும் பயன்படுத்த பரிந்துரைக்கிறோம்.

எதிர்காலத்தில், CSS library-களின் preset-களில் இது built-in ஆக இருக்கலாம்.

View Transition Class

எந்த animation-கள் trigger ஆக வேண்டும் என்பதை வரையறுக்க <ViewTransition> props வழங்குகிறது:

<ViewTransition
default="none"
enter="slide-up"
exit="slide-down"
/>

Props

  • optional enter: "auto", "none", a string, or an object.
  • optional exit: "auto", "none", a string, or an object.
  • optional update: "auto", "none", a string, or an object.
  • optional share: "auto", "none", a string, or an object.
  • optional default: "auto", "none", a string, or an object.

எச்சரிக்கைகள்

  • default "none" ஆக இருந்தால், வெளிப்படையாக பட்டியலிடப்படாத அனைத்து trigger-களும் off செய்யப்படும்.

மதிப்புகள்

View Transition class value-கள் இவையாக இருக்கலாம்:

  • auto: default. browser default animation-ஐப் பயன்படுத்தும்.
  • none: இந்த வகைக்கான animation-களை disable செய்யும்.
  • <classname>: View Transition-களை customize செய்ய பயன்படுத்தும் custom CSS class name.

Object value-கள் string key-களும் auto, none அல்லது custom className மதிப்பும் கொண்ட object ஆக இருக்கலாம்:

  • {[type]: value}: animation Transition Type-க்கு match ஆனால் value-ஐ apply செய்கிறது.
  • {default: value}: எந்த Transition Type-மும் match ஆகாவிட்டால் apply செய்யப்படும் default value.

உதாரணமாக, ViewTransition-ஐ இவ்வாறு define செய்யலாம்:

<ViewTransition
/* turn off any animation not defined below */
default="none"
enter={{
/* apply slide-in for Transition Type `forward` */
"forward": 'slide-in',
/* otherwise use the browser default animation */
"default": 'auto'
}}
/* use the browser default for exit animations*/
exit="auto"
/* apply a custom `cross-fade` class for updates */
update="cross-fade"
>

custom animation-களுக்கான CSS class-களை எப்படி define செய்வது என்பதை Styling View Transitions-இல் பார்க்கவும்.


View Transition Event

View Transition Event-கள் Web Animations API-யைப் பயன்படுத்தி JavaScript மூலம் animation-ஐ control செய்ய அனுமதிக்கின்றன:

<ViewTransition
onEnter={instance => {/* ... */}}
onExit={instance => {/* ... */}}
/>

Props

  • optional onEnter: “enter” animation trigger ஆகும் போது call செய்யப்படும்.
  • optional onExit: “exit” animation trigger ஆகும் போது call செய்யப்படும்.
  • optional onShare: “share” animation trigger ஆகும் போது call செய்யப்படும்.
  • optional onUpdate: “update” animation trigger ஆகும் போது call செய்யப்படும்.

எச்சரிக்கைகள்

  • ஒவ்வொரு Transition-க்கும் ஒவ்வொரு <ViewTransition>-க்கு ஒரு event மட்டுமே fire ஆகும். onEnter மற்றும் onExit-ஐ விட onShare முன்னுரிமை பெறுகிறது.
  • ஒவ்வொரு event-மும் cleanup function ஒன்றை return செய்ய வேண்டும். View Transition முடிந்ததும் cleanup function call செய்யப்படும்; இதனால் எந்த animation-களையும் cancel அல்லது cleanup செய்ய முடியும்.

Argument-கள்

ஒவ்வொரு event-க்கும் இரண்டு argument-கள் கிடைக்கும்:

  • instance: view transition pseudo-element-களுக்கு அணுகலை வழங்கும் View Transition instance.
    • old: ::view-transition-old pseudo-element.
    • new: ::view-transition-new pseudo-element.
    • name: இந்த boundary-க்கான view-transition-name string.
    • group: ::view-transition-group pseudo-element.
    • imagePair: ::view-transition-image-pair pseudo-element.
  • types: animation-இல் உள்ள Transition Type-களின் Array<string>. type எதுவும் குறிப்பிடப்படவில்லை என்றால் காலியான array.

உதாரணமாக, JavaScript மூலம் animation-ஐ இயக்கும் onEnter event ஒன்றை define செய்யலாம்:

<ViewTransition
onEnter={(instance, types) => {
const anim = instance.new.animate([{opacity: 0}, {opacity: 1}], {
duration: 500,
});
return () => anim.cancel();
}}>
<div>...</div>
</ViewTransition>

மேலும் உதாரணங்களுக்கு Animating with JavaScript பார்க்கவும்.


View Transition-களை style செய்தல்

Note

web-இல் உள்ள View Transition-களின் பல ஆரம்ப உதாரணங்களில், view-transition-name-ஐப் பயன்படுத்தி, பிறகு ::view-transition-...(my-name) selector-கள் மூலம் style செய்வதை பார்த்திருப்பீர்கள். styling-க்கு அதை பரிந்துரைக்கவில்லை. அதற்கு பதிலாக பொதுவாக View Transition Class-ஐப் பயன்படுத்த பரிந்துரைக்கிறோம்.

<ViewTransition>-க்கான animation-ஐ customize செய்ய, activation prop-களில் ஒன்றுக்கு View Transition Class வழங்கலாம். View Transition activate ஆகும் போது child element-களுக்கு React apply செய்யும் CSS class name-தான் View Transition Class.

உதாரணமாக, “enter” animation-ஐ customize செய்ய, enter prop-க்கு class name ஒன்றை வழங்குங்கள்:

<ViewTransition enter="slide-in">

<ViewTransition> “enter” animation-ஐ activate செய்யும்போது, React slide-in class name-ஐச் சேர்க்கும். பிறகு reusable animation-களை உருவாக்க view transition pseudo selector-களை பயன்படுத்தி இந்த class-ஐ refer செய்யலாம்:

::view-transition-group(.slide-in) {
}
::view-transition-old(.slide-in) {
}
::view-transition-new(.slide-in) {
}

எதிர்காலத்தில், இதைப் பயன்படுத்த மேம்படுத்த CSS library-கள் View Transition Class-களைப் பயன்படுத்தி built-in animation-களைச் சேர்க்கலாம்.


Usage

enter/exit-இல் ஒரு element-ஐ animate செய்தல்

ஒரு transition-இல் component ஒன்று <ViewTransition>-ஐ சேர்க்கும்போது அல்லது நீக்கும்போது Enter/Exit Transition-கள் trigger ஆகும்:

function Child() {
return (
<ViewTransition enter="auto" exit="auto" default="none">
<div>வணக்கம்</div>
</ViewTransition>
);
}

function Parent() {
const [show, setShow] = useState();
if (show) {
return <Child />;
}
return null;
}

setShow call செய்யப்படும் போது, show true ஆக மாறி Child component render ஆகும். startTransition-க்குள் setShow call செய்யப்படும்போது, மேலும் Child வேறு எந்த DOM node-க்கும் முன் ViewTransition-ஐ render செய்தால், enter animation trigger ஆகும்.

show மீண்டும் false ஆக மாறும்போது, exit animation trigger ஆகும்.

import {ViewTransition, useState, startTransition} from 'react';
import {Video} from './Video';
import videos from './data';

function Item() {
  return (
    <ViewTransition enter="auto" exit="auto" default="none">
      <Video video={videos[0]} />
    </ViewTransition>
  );
}

export default function Component() {
  const [showItem, setShowItem] = useState(false);
  return (
    <>
      <button
        onClick={() => {
          startTransition(() => {
            setShowItem((prev) => !prev);
          });
        }}>
        {showItem ? '➖' : '➕'}
      </button>

      {showItem ? <Item /> : null}
    </>
  );
}

Pitfall

top-level ViewTransition-கள் மட்டுமே exit/enter-இல் animate ஆகும்

<ViewTransition> எந்த DOM node-க்கும் முன் வைக்கப்பட்டால் மட்டுமே exit/enter-ஐ activate செய்யும்.

<ViewTransition>-க்கு மேலே <div> இருந்தால், exit/enter animation எதுவும் trigger ஆகாது:

function Item() {
return (
<div> {/* 🚩<div> above <ViewTransition> breaks exit/enter */}
<ViewTransition enter="auto" exit="auto" default="none">
<Video video={videos[0]} />
</ViewTransition>
</div>
);
}

அதிகமாகவோ குறைவாகவோ animate ஆகும் நுணுக்கமான bug-களை இந்த கட்டுப்பாடு தடுக்கிறது.


Activity உடன் enter/exit-ஐ animate செய்தல்

ஒரு component-ன் state-ஐப் பாதுகாத்தபடி அதை உள்ளே/வெளியே animate செய்ய, அல்லது animation-க்காக content-ஐ pre-render செய்ய விரும்பினால், <Activity>-ஐப் பயன்படுத்தலாம். <Activity>-க்குள் உள்ள <ViewTransition> visible ஆகும்போது, enter animation activate ஆகும். அது hidden ஆகும்போது, exit animation activate ஆகும்:

<Activity mode={isVisible ? 'visible' : 'hidden'}>
<ViewTransition enter="auto" exit="auto">
<Counter />
</ViewTransition>
</Activity>

இந்த உதாரணத்தில், Counter-க்கு internal state உடைய counter உள்ளது. counter-ஐ increment செய்து, அதை hide செய்து, பிறகு மீண்டும் show செய்து பாருங்கள். sidebar உள்ளே/வெளியே animate ஆகும்போது counter-ன் மதிப்பு பாதுகாக்கப்படுகிறது:

import { Activity, ViewTransition, useState, startTransition } from 'react';

export default function App() {
  const [show, setShow] = useState(true);
  return (
    <div className="layout">
      <Toggle show={show} setShow={setShow} />
      <Activity mode={show ? 'visible' : 'hidden'}>
        <ViewTransition enter="auto" exit="auto" default="none">
          <Counter />
        </ViewTransition>
      </Activity>
    </div>
  );
}
function Toggle({show, setShow}) {
  return (
    <button
      className="toggle"
      onClick={() => {
        startTransition(() => {
          setShow(s => !s);
        });
      }}>
      {show ? 'மறை' : 'காட்டு'}
    </button>
  )
}
function Counter() {
  const [count, setCount] = useState(0);
  return (
    <div className="counter">
      <h2>எண்ணி</h2>
      <p>எண்ணிக்கை: {count}</p>
      <button onClick={() => setCount(count + 1)}>
        அதிகரி
      </button>
    </div>
  );
}

<Activity> இல்லாமல், sidebar மீண்டும் தோன்றும் ஒவ்வொரு முறையும் counter 0-க்கு reset ஆகும்.


shared element ஒன்றை animate செய்தல்

பொதுவாக, <ViewTransition>-க்கு பெயர் assign செய்வதை பரிந்துரைக்க மாட்டோம்; அதற்கு பதிலாக React தானாக பெயர் assign செய்ய அனுமதிக்கிறோம். continuity-ஐப் பாதுகாக்க, ஒரு tree unmount ஆகி மற்றொரு tree அதே நேரத்தில் mount ஆகும்போது முற்றிலும் வேறு component-களுக்கிடையே animate செய்ய வேண்டுமெனில் பெயர் assign செய்ய விரும்பலாம்.

<ViewTransition name={UNIQUE_NAME}>
<Child />
</ViewTransition>

ஒரு tree unmount ஆகி மற்றொன்று mount ஆகும்போது, unmount ஆகும் tree-யிலும் mount ஆகும் tree-யிலும் அதே பெயர் இருக்கும் pair இருந்தால், அவை இரண்டிலும் “share” animation-ஐ trigger செய்யும். அது unmount ஆகும் பக்கத்திலிருந்து mount ஆகும் பக்கத்துக்கு animate செய்கிறது.

exit/enter animation-க்கு மாறாக, இது deleted/mounted tree-க்குள் ஆழமாக இருக்கலாம். ஒரு <ViewTransition> exit/enter-க்கும் eligible ஆக இருந்தால், “share” animation முன்னுரிமை பெறும்.

Transition முதலில் ஒரு பக்கத்தை unmount செய்து, பிறகு இறுதியில் புதிய பெயர் mount ஆகும் முன் <Suspense> fallback காட்டப்படுமாறு செய்தால், shared element transition நடக்காது.

import {ViewTransition, useState, startTransition} from 'react';
import {Video, Thumbnail, FullscreenVideo} from './Video';
import videos from './data';

export default function Component() {
  const [fullscreen, setFullscreen] = useState(false);
  if (fullscreen) {
    return (
      <FullscreenVideo
        video={videos[0]}
        onExit={() => startTransition(() => setFullscreen(false))}
      />
    );
  }
  return (
    <Video
      video={videos[0]}
      onClick={() => startTransition(() => setFullscreen(true))}
    />
  );
}

Note

ஒரு pair-இன் mounted அல்லது unmounted பக்கம் viewport-க்கு வெளியே இருந்தால், pair உருவாகாது. ஏதாவது scroll செய்யப்படும் போது அது viewport-க்கு உள்ளே அல்லது வெளியே பறந்து வராமல் இருப்பதை இது உறுதிசெய்கிறது. அதற்கு பதிலாக அது தனியாக regular enter/exit ஆக நடத்தப்படும்.

அதே Component instance position மாறினால் இது நடக்காது; அது “update”-ஐ trigger செய்கிறது. ஒரு position viewport-க்கு வெளியே இருந்தாலும் அவை animate ஆகும்.

ஆழமாக nested ஆன unmounted <ViewTransition> viewport-க்குள் இருந்தும் mounted பக்கம் viewport-க்குள் இல்லாத known case ஒன்று உள்ளது; அப்போது unmounted பக்கம் parent animation-ன் பகுதியாக அல்லாமல், அது ஆழமாக nested இருந்தாலும் தன் சொந்த “exit” animation ஆக animate ஆகும்.

Pitfall

முழு app-இல் ஒரே நேரத்தில் அதே பெயருடன் mount ஆன ஒன்று மட்டுமே இருப்பது முக்கியம். எனவே conflict-களைத் தவிர்க்க பெயருக்கு unique namespace-களைப் பயன்படுத்துவது முக்கியம். இதைச் செய்ய முடியும் என்பதை உறுதிசெய்ய, நீங்கள் import செய்யும் தனி module-இல் constant ஒன்றைச் சேர்க்கலாம்.

export const MY_NAME = "my-globally-unique-name";
import {MY_NAME} from './shared-name';
...
<ViewTransition name={MY_NAME}>

list-இல் item-களின் reorder-ஐ animate செய்தல்

items.map((item) => <Component key={item.id} item={item} />);

content-ஐ update செய்யாமல் list-ஐ reorder செய்யும்போது, அவை DOM node-க்கு வெளியே இருந்தால், list-இல் உள்ள ஒவ்வொரு <ViewTransition>-க்கும் “update” animation trigger ஆகும். enter/exit animation-களைப் போல.

இதன் பொருள், இது இந்த <ViewTransition>-இல் animation-ஐ trigger செய்யும்:

function Component() {
return (
<ViewTransition>
<div>...</div>
</ViewTransition>
);
}
import {ViewTransition, useState, startTransition} from 'react';
import {Video} from './Video';
import videos from './data';

export default function Component() {
  const [orderedVideos, setOrderedVideos] = useState(videos);
  const reorder = () => {
    startTransition(() => {
      setOrderedVideos((prev) => {
        return [...prev.sort(() => Math.random() - 0.5)];
      });
    });
  };
  return (
    <>
      <button onClick={reorder}>🎲</button>
      <div className="listContainer">
        {orderedVideos.map((video, i) => {
          return (
            <ViewTransition key={video.title}>
              <Video video={video} />
            </ViewTransition>
          );
        })}
      </div>
    </>
  );
}

ஆனால் இது ஒவ்வொரு தனிப்பட்ட item-ஐ animate செய்யாது:

function Component() {
return (
<div>
<ViewTransition>...</ViewTransition>
</div>
);
}

அதற்கு பதிலாக, parent <ViewTransition> ஏதேனும் இருந்தால் அது cross-fade ஆகும். parent <ViewTransition> இல்லையெனில், அந்தச் சூழலில் animation இல்லை.

import {ViewTransition, useState, startTransition} from 'react';
import {Video} from './Video';
import videos from './data';

export default function Component() {
  const [orderedVideos, setOrderedVideos] = useState(videos);
  const reorder = () => {
    startTransition(() => {
      setOrderedVideos((prev) => {
        return [...prev.sort(() => Math.random() - 0.5)];
      });
    });
  };
  return (
    <>
      <button onClick={reorder}>🎲</button>
      <ViewTransition>
        <div className="listContainer">
          {orderedVideos.map((video, i) => {
            return <Video video={video} key={video.title} />;
          })}
        </div>
      </ViewTransition>
    </>
  );
}

Component தன் சொந்த reorder animation-ஐ control செய்ய அனுமதிக்க விரும்பும் list-களில் wrapper element-களைத் தவிர்க்கலாம் என்பதைக் குறிக்கிறது:

items.map(item => <div><Component key={item.id} item={item} /></div>)

item-களில் ஒன்று resize ஆக update ஆகி, அதனால் sibling-களும் resize ஆகும் சூழலுக்கும் மேலுள்ள விதி பொருந்தும்; அவை immediate sibling-களாக இருந்தால் மட்டுமே அது sibling <ViewTransition>-ஐயும் animate செய்யும்.

அதாவது அதிக re-layout ஏற்படுத்தும் update-இன் போது, page-இல் உள்ள ஒவ்வொரு <ViewTransition>-யையும் தனித்தனியாக animate செய்யாது. அது உண்மையான மாற்றத்திலிருந்து கவனத்தைத் திருப்பும் பல noisy animation-களுக்கு வழிவகுக்கும். எனவே தனிப்பட்ட animation எப்போது trigger ஆக வேண்டும் என்பதில் React சற்றுக் கவனமாக இருக்கும்.

Pitfall

list-களை reorder செய்யும்போது identity-ஐப் பாதுகாக்க key-களை சரியாகப் பயன்படுத்துவது முக்கியம். reorder-களை animate செய்ய “name”, shared element transition-களைப் பயன்படுத்தலாம் போல தோன்றலாம்; ஆனால் ஒரு பக்கம் viewport-க்கு வெளியே இருந்தால் அது trigger ஆகாது. reorder-ஐ animate செய்யும்போது அது viewport-க்கு வெளியே உள்ள position-க்கு சென்றதைப் பல நேரங்களில் காட்ட விரும்புவீர்கள்.


Suspense content-இலிருந்து animate செய்தல்

எந்த Transition போலவே, animation ஓடுவதற்கு முன் data மற்றும் புதிய CSS (<link rel="stylesheet" precedence="...">) க்காக React காத்திருக்கும். இதற்கு கூடுதலாக, புதிய font-கள் பின்னர் flicker ஆகாமல் இருக்க animation தொடங்குவதற்கு முன் ViewTransition-கள் அவை load ஆக 500ms வரை காத்திருக்கும். அதே காரணத்திற்காக, ViewTransition-இல் wrap செய்யப்பட்ட image, image load ஆக காத்திருக்கும்.

இது புதிய Suspense boundary instance-க்குள் இருந்தால், fallback முதலில் காட்டப்படும். Suspense boundary முழுமையாக load ஆன பிறகு, content reveal-ஐ animate செய்ய அது <ViewTransition>-ஐ trigger செய்கிறது.

<ViewTransition>-ஐ எங்கே வைக்கிறீர்கள் என்பதன் அடிப்படையில் Suspense boundary-களை animate செய்ய இரண்டு வழிகள் உள்ளன:

Update:

<ViewTransition>
<Suspense fallback={<A />}>
<B />
</Suspense>
</ViewTransition>

இந்தச் சூழலில் content A-இலிருந்து B-க்கு மாறும்போது, அது “update” ஆக நடத்தப்படும்; பொருத்தமானால் அந்த class apply செய்யப்படும். A மற்றும் B இரண்டுக்கும் அதே view-transition-name கிடைக்கும், எனவே இயல்பாக அவை cross-fade போல செயல்படும்.

import {ViewTransition, useState, startTransition, Suspense} from 'react';
import {Video, VideoPlaceholder} from './Video';
import {useLazyVideoData} from './data';

function LazyVideo() {
  const video = useLazyVideoData();
  return <Video video={video} />;
}

export default function Component() {
  const [showItem, setShowItem] = useState(false);
  return (
    <>
      <button
        onClick={() => {
          startTransition(() => {
            setShowItem((prev) => !prev);
          });
        }}>
        {showItem ? '➖' : '➕'}
      </button>
      {showItem ? (
        <ViewTransition>
          <Suspense fallback={<VideoPlaceholder />}>
            <LazyVideo />
          </Suspense>
        </ViewTransition>
      ) : null}
    </>
  );
}

Enter/Exit:

<Suspense fallback={<ViewTransition><A /></ViewTransition>}>
<ViewTransition><B /></ViewTransition>
</Suspense>

இந்தச் சூழலில், இவை தத்தமுடைய view-transition-name கொண்ட இரண்டு தனித்தனி ViewTransition instance-கள். இது <A>-ன் “exit” மற்றும் <B>-ன் “enter” ஆக நடத்தப்படும்.

<ViewTransition> boundary-ஐ எங்கே வைக்கிறீர்கள் என்பதன் அடிப்படையில் வேறு effect-களைப் பெறலாம்.


animation ஒன்றிலிருந்து opt out செய்தல்

சில நேரங்களில் முழு page போன்ற பெரிய existing component ஒன்றை wrap செய்து, theme மாற்றம் போன்ற சில update-களை animate செய்ய விரும்பலாம். ஆனால் முழு page-க்குள் update ஆகும் எல்லா update-களும் cross-fade ஆக opt-in ஆக வேண்டாம் என்று நினைக்கலாம். குறிப்பாக நீங்கள் animation-களை படிப்படியாகச் சேர்க்கும்போது.

animation ஒன்றிலிருந்து opt out செய்ய “none” class-ஐப் பயன்படுத்தலாம். உங்கள் children-ஐ “none”-இல் wrap செய்வதன் மூலம், parent இன்னும் trigger ஆகினாலும் அவற்றின் update-களுக்கான animation-களை disable செய்யலாம்.

<ViewTransition>
<div className={theme}>
<ViewTransition update="none">{children}</ViewTransition>
</div>
</ViewTransition>

theme மாறினால் மட்டுமே இது animate ஆகும்; children மட்டும் update ஆனால் அல்ல. children தங்களுடைய <ViewTransition> மூலம் மீண்டும் opt-in ஆகலாம், ஆனால் குறைந்தது அது மீண்டும் manual ஆக இருக்கும்.


animation-களை customize செய்தல்

இயல்பாக, <ViewTransition> browser-இலிருந்து default cross-fade-ஐ உட்கொண்டுள்ளது.

animation-களை customize செய்ய, <ViewTransition> எப்படி activate ஆகிறது என்பதன் அடிப்படையில் எந்த animation-களை பயன்படுத்த வேண்டும் என்பதை குறிப்பிட <ViewTransition> component-க்கு props வழங்கலாம்.

உதாரணமாக, default cross fade animation-ஐ மெதுவாக்கலாம்:

<ViewTransition default="slow-fade">
<Video />
</ViewTransition>

மேலும் view transition class-களைப் பயன்படுத்தி CSS-இல் slow-fade-ஐ define செய்யலாம்:

::view-transition-old(.slow-fade) {
animation-duration: 500ms;
}

::view-transition-new(.slow-fade) {
animation-duration: 500ms;
}
import {ViewTransition, useState, startTransition} from 'react';
import {Video} from './Video';
import videos from './data';

function Item() {
  return (
    <ViewTransition default="slow-fade">
      <Video video={videos[0]} />
    </ViewTransition>
  );
}

export default function Component() {
  const [showItem, setShowItem] = useState(false);
  return (
    <>
      <button
        onClick={() => {
          startTransition(() => {
            setShowItem((prev) => !prev);
          });
        }}>
        {showItem ? '➖' : '➕'}
      </button>

      {showItem ? <Item /> : null}
    </>
  );
}

default-ஐ அமைப்பதற்குப் கூடுதலாக, enter, exit, update, மற்றும் share animation-களுக்கான configuration-களையும் வழங்கலாம்.

import {ViewTransition, useState, startTransition} from 'react';
import {Video} from './Video';
import videos from './data';

function Item() {
  return (
    <ViewTransition enter="slide-in" exit="slide-out">
      <Video video={videos[0]} />
    </ViewTransition>
  );
}

export default function Component() {
  const [showItem, setShowItem] = useState(false);
  return (
    <>
      <button
        onClick={() => {
          startTransition(() => {
            setShowItem((prev) => !prev);
          });
        }}>
        {showItem ? '➖' : '➕'}
      </button>

      {showItem ? <Item /> : null}
    </>
  );
}


type-களுடன் animation-களை customize செய்தல்

குறிப்பிட்ட activation trigger-க்கு குறிப்பிட்ட transition type activate ஆகும்போது child element-களுக்கு class name சேர்க்க addTransitionType API-யைப் பயன்படுத்தலாம். இது ஒவ்வொரு transition type-க்கும் animation-ஐ customize செய்ய அனுமதிக்கிறது.

உதாரணமாக, அனைத்து forward மற்றும் backward navigation-களுக்கான animation-ஐ customize செய்ய:

<ViewTransition
default={{
'navigation-back': 'slide-right',
'navigation-forward': 'slide-left',
}}>
<div>...</div>
</ViewTransition>;

// in your router:
startTransition(() => {
addTransitionType('navigation-' + navigationType);
});

ViewTransition “navigation-back” animation-ஐ activate செய்யும்போது, React “slide-right” class name-ஐச் சேர்க்கும். ViewTransition “navigation-forward” animation-ஐ activate செய்யும்போது, React “slide-left” class name-ஐச் சேர்க்கும்.

எதிர்காலத்தில், router-களும் பிற library-களும் standard view-transition type-களுக்கும் style-களுக்கும் support சேர்க்கலாம்.

import {
  ViewTransition,
  addTransitionType,
  useState,
  startTransition,
} from 'react';
import {Video} from './Video';
import videos from './data';

function Item() {
  return (
    <ViewTransition
      enter={{
        'add-video-back': 'slide-in-back',
        'add-video-forward': 'slide-in-forward',
      }}
      exit={{
        'remove-video-back': 'slide-in-forward',
        'remove-video-forward': 'slide-in-back',
      }}>
      <Video video={videos[0]} />
    </ViewTransition>
  );
}

export default function Component() {
  const [showItem, setShowItem] = useState(false);
  return (
    <>
      <div className="button-container">
        <button
          onClick={() => {
            startTransition(() => {
              if (showItem) {
                addTransitionType('remove-video-back');
              } else {
                addTransitionType('add-video-back');
              }
              setShowItem((prev) => !prev);
            });
          }}>
          ⬅️
        </button>
        <button
          onClick={() => {
            startTransition(() => {
              if (showItem) {
                addTransitionType('remove-video-forward');
              } else {
                addTransitionType('add-video-forward');
              }
              setShowItem((prev) => !prev);
            });
          }}>
          ➡️
        </button>
      </div>
      {showItem ? <Item /> : null}
    </>
  );
}


JavaScript மூலம் animate செய்தல்

View Transition Class-கள் CSS மூலம் animation-களை define செய்ய அனுமதித்தாலும், சில நேரங்களில் animation மீது imperative control தேவைப்படும். onEnter, onExit, onUpdate, மற்றும் onShare callback-கள் view transition pseudo-element-களுக்கு நேரடி அணுகலை வழங்குகின்றன; எனவே Web Animations API-யைப் பயன்படுத்தி அவற்றை animate செய்யலாம்.

ஒவ்வொரு callback-க்கும் view transition pseudo-element-களை பிரதிநிதித்துவப்படுத்தும் .old மற்றும் .new property-கள் கொண்ட instance கிடைக்கும். DOM element-இல் செய்வது போலவே அவற்றிலும் .animate()-ஐ call செய்யலாம்:

<ViewTransition
onEnter={(instance) => {
const anim = instance.new.animate(
[
{transform: 'scale(0.8)'},
{transform: 'scale(1)'},
],
{duration: 300, easing: 'ease-out'}
);
return () => anim.cancel();
}}>
<div>...</div>
</ViewTransition>

இது CSS-driven animation-களையும் JavaScript-driven animation-களையும் இணைக்க அனுமதிக்கிறது.

பின்வரும் உதாரணத்தில், default cross-fade CSS மூலம் கையாளப்படுகிறது; slide animation-கள் onEnter மற்றும் onExit animation-களில் JavaScript மூலம் இயக்கப்படுகின்றன:

import {ViewTransition, useState, startTransition} from 'react';
import {Video} from './Video';
import videos from './data';
import {SLIDE_IN, SLIDE_OUT} from './animations';

function Item() {
  return (
    <ViewTransition
      default="none"
      /* CSS driven cross fade defaults */
      enter="auto"
      exit="auto"
      /* JS driven slide animations */
      onEnter={(instance) => {
        const anim = instance.new.animate(
          SLIDE_IN,
          {duration: 500, easing: 'ease-out'}
        );
        return () => anim.cancel();
      }}
      onExit={(instance) => {
        const anim = instance.old.animate(
          SLIDE_OUT,
          {duration: 300, easing: 'ease-in'}
        );
        return () => anim.cancel();
      }}>
      <Video video={videos[0]} />
    </ViewTransition>
  );
}

export default function Component() {
  const [showItem, setShowItem] = useState(false);
  return (
    <>
      <button
        onClick={() => {
          startTransition(() => {
            setShowItem((prev) => !prev);
          });
        }}>
        {showItem ? '➖' : '➕'}
      </button>

      {showItem ? <Item /> : null}
    </>
  );
}

Note

View Transition Event-களை எப்போதும் clean up செய்யுங்கள்

View Transition Event-கள் எப்போதும் cleanup function ஒன்றை return செய்ய வேண்டும்:

<ViewTransition
onEnter={(instance) => {
const anim = instance.new.animate(
SLIDE_IN,
{duration: 500, easing: 'ease-out'}
);
return () => anim.cancel();
}}
>

View Transition interrupt செய்யப்படும் போது animation-ஐ cancel செய்ய இது browser-க்கு அனுமதிக்கிறது.


JavaScript மூலம் transition type-களை animate செய்தல்

Transition எப்படி trigger செய்யப்பட்டது என்பதன் அடிப்படையில் வேறு animation-களை conditionally apply செய்ய, ViewTransition event-களுக்கு pass செய்யப்படும் types-ஐப் பயன்படுத்தலாம்.

<ViewTransition
onEnter={(instance, types) => {
const duration = types.includes('fast') ? 150 : 2000;
const anim = instance.new.animate(
SLIDE_IN,
{duration: duration, easing: 'ease-out'}
);
return () => anim.cancel();
}}
>

இந்த உதாரணம் Transition-ஐ “fast” என குறிக்க addTransitionType-ஐ call செய்து, பின்னர் animation duration-ஐ adjust செய்கிறது:

import {ViewTransition, useState, startTransition, addTransitionType} from 'react';
import {Video} from './Video';
import videos from './data';
import {SLIDE_IN, SLIDE_OUT} from './animations';

function Item() {
  return (
    <ViewTransition
      onEnter={(instance, types) => {
        const duration = types.includes('fast') ? 150 : 2000;
        const anim = instance.new.animate(
          SLIDE_IN,
          {duration: duration, easing: 'ease-out'}
        );
        return () => anim.cancel();
      }}
      onExit={(instance, types) => {
        const duration = types.includes('fast') ? 150 : 500;
        const anim = instance.old.animate(
          SLIDE_OUT,
          {duration: duration, easing: 'ease-in'}
        );
        return () => anim.cancel();
      }}>
      <Video video={videos[0]} />
    </ViewTransition>
  );
}

export default function Component() {
  const [showItem, setShowItem] = useState(false);
  const [isFast, setIsFast] = useState(false);
  return (
    <>
      <div>
        வேகம்: <input type="checkbox" onChange={() => {setIsFast(f => !f)}} value={isFast}></input>
      </div><br />
      <button
        onClick={() => {
          startTransition(() => {
            if (isFast) {
              addTransitionType('fast');
            }
            setShowItem((prev) => !prev);
          });
        }}>
        {showItem ? '➖' : '➕'}
      </button>

      {showItem ? <Item /> : null}
    </>
  );
}


View Transition enabled router-களை உருவாக்குதல்

scroll restoration animation-க்குள் நடப்பதை உறுதிசெய்ய, pending Navigation ஏதேனும் முடியும் வரை React காத்திருக்கும். Navigation React-இல் blocked ஆக இருந்தால், useEffect deadlock-க்கு வழிவகுக்கும் என்பதால், உங்கள் router useLayoutEffect-இல் unblock செய்ய வேண்டும்.

legacy popstate event-இலிருந்து startTransition தொடங்கப்பட்டால், உதாரணமாக “back” navigation-இன் போது, scroll மற்றும் form restoration சரியாக வேலை செய்வதை உறுதிசெய்ய அது synchronously முடிக்கப்பட வேண்டும். இது View Transition animation ஓடுவதுடன் முரண்படும். எனவே React popstate-இலிருந்து வரும் animation-களை skip செய்யும்; back button-க்கு animation ஓடாது. உங்கள் router-ஐ Navigation API பயன்படுத்துமாறு upgrade செய்வதன் மூலம் இதைச் சரிசெய்யலாம்.


Troubleshooting

என் <ViewTransition> activate ஆகவில்லை

<ViewTransition> எந்த DOM node-க்கும் முன் வைக்கப்பட்டால் மட்டுமே activate ஆகும்:

function Component() {
return (
<div>
<ViewTransition>வணக்கம்</ViewTransition>
</div>
);
}

சரிசெய்ய, <ViewTransition> மற்ற எந்த DOM node-க்கும் முன் வருவதை உறுதிசெய்யுங்கள்:

function Component() {
return (
<ViewTransition>
<div>வணக்கம்</div>
</ViewTransition>
);
}

“There are two <ViewTransition name=%s> components with the same name mounted at the same time.” என்ற error வருகிறது

ஒரே name கொண்ட இரண்டு <ViewTransition> component-கள் ஒரே நேரத்தில் mount ஆனால் இந்த error ஏற்படும்:

function Item() {
// 🚩 All items will get the same "name".
return <ViewTransition name="item">...</ViewTransition>;
}

function ItemList({items}) {
return (
<>
{items.map((item) => (
<Item key={item.id} />
))}
</>
);
}

இதனால் View Transition error ஆகும். development-இல், React இந்த issue-வை வெளிக்காட்ட detect செய்து இரண்டு error-களை log செய்கிறது:

Console
There are two <ViewTransition name=%s> components with the same name mounted at the same time. This is not supported and will cause View Transitions to error. Try to use a more unique name e.g. by using a namespace prefix and adding the id of an item to the name. at Item at ItemList
The existing <ViewTransition name=%s> duplicate has this stack trace. at Item at ItemList

சரிசெய்ய, name unique என்பதை உறுதிசெய்தோ அல்லது பெயருக்கு id சேர்த்தோ, முழு app-இல் ஒரே நேரத்தில் அதே பெயருடன் ஒரே ஒரு <ViewTransition> மட்டுமே mount ஆகும் என்பதை உறுதிசெய்யுங்கள்:

function Item({id}) {
// ✅ All items will get a unique name.
return <ViewTransition name={`item-${id}`}>...</ViewTransition>;
}

function ItemList({items}) {
return (
<>
{items.map((item) => (
<Item key={item.id} item={item} />
))}
</>
);
}