React ViewTransition مش شغال؟ كل الحلول (2026)
١٢ يونيو ٢٠٢٦
مكون React <ViewTransition> الذي يرفض التحريك بصمت غالباً ما يكون له أحد أربعة أسباب: تحديث الحالة ليس مغلفاً بـ startTransition، أو المكون ليس موضوعاً قبل أي عقدة DOM أخرى، أو أنك تستخدم إصدار React المستقر بدلاً من إصدار canary، أو أن المتصفح لا يدعم View Transition API.
ملخص
مكون <ViewTransition> الخاص بـ React يغلف View Transition API للمتصفح، لكنه لا يعمل إلا في ظل ظروف محددة ليست واضحة في العروض التوضيحية البسيطة. استخدام setState العادي لا يحفزه أبداً — فقط Transitions، و Suspense reveals، و useDeferredValue هي ما تفعل ذلك. يجب أن يتواجد فوق أي عقدة DOM في مخرجات المكون ليعمل تحريك الدخول/الخروج (enter/exit)، وهو يتوفر فقط في قنوات Canary و Experimental الخاصة بـ React، وليس في إصدار React 19.2 المستقر.1 تتبع الأسباب الأربعة أدناه بالترتيب؛ أحدها هو سبب المشكلة لديك.
ما ستتعلمه
- الأسباب الأربعة وراء كل فشل صامت لـ
<ViewTransition>تقريباً، وبالترتيب الذي يجب فحصها به - لماذا لا يقوم React بتحريك التحديثات إلا إذا كانت مغلفة بـ
startTransitionأو<Suspense>أوuseDeferredValue - قاعدة وضع الـ DOM التي تعطل تحريكات الدخول والخروج بهدوء
- أي إصدارات وقنوات إصدار React تتضمن بالفعل
<ViewTransition> - دعم المتصفحات الحالي لـ View Transition API، بما في ذلك Safari و Firefox
- لماذا لا يتم تحريك التنقل عبر زر الرجوع أبداً، وكيفية إصلاح ذلك باستخدام Navigation API
- كيفية تخصيص التحريكات باستخدام View Transition Classes وأنواع الانتقالات وأحداث JavaScript
- كيف يتناسب
<ViewTransition>مع Next.js و React Router اليوم
لماذا لا يعمل ViewTransition في React الخاص بي؟
من الناحية العملية، هناك أربعة أسباب تفسر تقريباً كل تقرير عن "عدم وجود تحريك": تحديث حالة متزامن، أو وضع خاطئ في الـ DOM، أو قناة إصدار React خاطئة، أو متصفح لا يدعم View Transition API. افحصها بهذا الترتيب — فهو أسرع طريق للوصول إلى السبب.
- التحديث متزامن. استخدام
setStateخارجstartTransitionيتم تنفيذه فوراً ويتجنب التحريك حسب التصميم.1 - مكون
<ViewTransition>يقع تحت عقدة DOM. وجود عنصر<div>واحد مغلف فوقه يعطل تحريكات الدخول/الخروج.1 - أنت تستخدم إصدار React المستقر. مكون
<ViewTransition>موجود فقط في قناتي Canary و Experimental؛ استيراده من إصدار React 19.2 المستقر سيفشل.1 - المتصفح يفتقر للدعم. بدون View Transition API، يقوم React بتطبيق تحديث الـ DOM بدون أي تحريك — وبدون خطأ أو تحذير.2
هناك أيضاً ثلاث نقاط دقيقة تستحق المعرفة حتى بعد عمل التحريكات: يتخطى React الانتقال تماماً إذا تم تنفيذ flushSync في منتصف التسلسل، وينتظر حتى 500 مللي ثانية للخطوط الجديدة (وللصور المغلفة) قبل البدء، كما أن وجود مكونين <ViewTransition> مفعلين يتشاركان في نفس الـ name يؤدي لظهور خطأ في بيئة التطوير.1
لماذا لا يقوم ViewTransition بالتحريك إلا داخل startTransition؟
هذا هو أول شيء يجب استبعاده. الحل هو غلاف واحد:
import { ViewTransition, startTransition, useState } from 'React';
function Gallery() {
const [show, setShow] = useState(false);
return (
<>
<button
onClick={() => {
startTransition(() => { // without this: no animation
setShow((prev) => !prev);
});
}}>
Toggle
</button>
{show ? (
<ViewTransition enter="auto" exit="auto" default="none">
<img src="/hero.jpg" alt="" />
</ViewTransition>
) : null}
</>
);
}
كلا الجزأين مطلوبان: <ViewTransition> يحدد ماذا سيتم تحريكه، و startTransition يحدد متى. لاحظ أنه لا يجب عليك أبداً استدعاء document.startViewTransition() بنفسك — React يستدعيها في الخلفية وسيقوم بمقاطعة أي انتقال عرض لم يبدأه هو بنفسه.1
لماذا لا يعمل تحريك الدخول أو الخروج الخاص بي؟
لا يقوم <ViewTransition> بتفعيل الدخول/الخروج إلا إذا تم وضعه قبل أي عقدة DOM في الشجرة التي يعيدها المكون الخاص بك.1 إذا قام عنصر <div> (أو أي عنصر مضيف) بتغليفه، فإن تحريكات الدخول والخروج ستتوقف عن العمل بصمت.
// 🚩 Broken: <div> above <ViewTransition> disables enter/exit
function Item() {
return (
<div>
<ViewTransition enter="auto" exit="auto">
<Video />
</ViewTransition>
</div>
);
}
// ✅ Works: ViewTransition comes first
function Item() {
return (
<ViewTransition enter="auto" exit="auto">
<div><Video /></div>
</ViewTransition>
);
}
نفس القاعدة تنطبق على تحريكات إعادة ترتيب القوائم: يتم تحريك العناصر بشكل فردي فقط عندما يكون <ViewTransition> لكل عنصر خارج أي عقدة DOM مغلفة، لذا تجنب أنماط مثل items.map(item => <div><Item /></div>) إذا كنت تريد حركة لكل عنصر على حدة.1 React متحفظ عمداً هنا — هذا القيد موجود لمنع تحريك أجزاء كثيرة جداً أو قليلة جداً من الصفحة.
أي إصدار من React تحتاجه لـ ViewTransition؟
مكون <ViewTransition> متاح فقط في قناتي إصدار Canary و Experimental الخاصة بـ React — وهو ليس جزءاً من أي إصدار مستقر، بما في ذلك خط إصدار React 19.2 الحالي.1 تم الإعلان عنه في منشور React Labs بتاريخ 23 أبريل 2025، ولا يزال مقيداً بقناة canary حتى يونيو 2026.3
لتجربته خارج إطار عمل:
npm install React@canary React-dom@canary
import { ViewTransition, startTransition } from 'React';
إذا قمت باستيراد ViewTransition من إصدار React المستقر، فستحصل على ربط غير معرف (undefined) أو خطأ في البناء بدلاً من رسالة مفيدة — وهو فشل آخر يسهل التغافل عنه. Next.js App Router هو الاستثناء الملحوظ: فهو يشحن إصدارات React canary، لذا يعمل الاستيراد هناك بمجرد تفعيل علامة إطار العمل (التفاصيل أدناه).4
أي المتصفحات تدعم View Transition API؟
انتقالات العرض داخل نفس المستند (Same-document view transitions) — النوع الذي يستخدمه مكون React — مدعومة في Chrome 111+، و Safari 18+، و Firefox 144+ (تم إصداره في أكتوبر 2025)، وهي الآن متاحة كـ Baseline Newly.25 أما الانتقالات عبر المستندات (Cross-document transitions) (للتطبيقات متعددة الصفحات) فهي أضيق نطاقاً: Chrome 126+، و Edge 126+، و Safari 18.2+، مع دعم جزئي فقط في Firefox 144+.6
نتيجتان عمليتان:
- المتصفحات غير المدعومة تتراجع بأمان. لا يزال تحديث الـ DOM مطبقاً؛ لكنه لا يكون متحركاً فقط. لا تحتاج إلى فرع لاكتشاف الميزات (feature-detection) من أجل الصحة البرمجية — فقط إذا كنت تريد تحريكاً بديلاً.2
- لا تقم بتصحيح الأخطاء في المتصفح الخاطئ. إذا كنت تختبر في إصدار قديم من Firefox ESR أو Safari قبل الإصدار 18، فقد يكون الكود الخاص بك سليماً. تحقق في إصدار حديث من Chrome أولاً، ثم توسع.
ملاحظة حول إمكانية الوصول: React لا يقوم بتعطيل هذه الحركات تلقائيًا للمستخدمين الذين لديهم إعداد prefers-reduced-motion — من المتوقع أن تقوم بتقليلها بنفسك باستخدام استعلام الوسائط (media query).1
لماذا لا تتحرك الرسوم عند الضغط على زر الرجوع؟
يتعمد React تخطي حركات انتقال العرض (view transition) للتنقلات التي يتم تشغيلها بواسطة حدث popstate القديم — وهو ما يتم إطلاقه عند الضغط على زر الرجوع في المتصفح.1 يجب أن ينتهي أي startTransition يبدأ من popstate بشكل متزامن (synchronously) حتى يعمل استعادة التمرير (scroll) والنماذج (forms) بشكل صحيح، وهذا لا يتوافق مع تشغيل انتقال عرض غير متزامن (async).
الحل الرسمي هو ترقية الراوتر الخاص بك إلى Navigation API، والذي لا يحمل قيود الاستعادة المتزامنة.1 إذا كنت تستخدم راوتر خاص بإطار عمل (framework)، فهذه وظيفة إطار العمل — تحقق مما إذا كان إصدار الراوتر الخاص بك يستخدم Navigation API قبل الإبلاغ عن مشكلة تتعلق بعدم تحرك الرسوم عند الرجوع.
كيف يمكنك تخصيص حركات ViewTransition؟
لديك ثلاث طبقات من التحكم: خصائص View Transition Class للرسوم المتحركة المعتمدة على CSS، وأنواع الانتقالات (transition types) للمتغيرات المعتمدة على السياق، ومعاودات الاتصال بالأحداث (event callbacks) للتحكم الكامل عبر JavaScript من خلال Web Animations API.1
فئات انتقال العرض (View Transition Classes). قم بتمرير فئة (class) إلى enter، أو exit، أو update، أو share، أو default، ثم استهدفها باستخدام محددات view-transition الزائفة (pseudo-selectors):
<ViewTransition enter="slide-in" default="slow-fade">
::view-transition-old(.slow-fade),
::view-transition-new(.slow-fade) {
animation-duration: 500ms;
}
كن حذرًا مع default="none" — فهو يوقف كل مشغل لم يتم إدراجه صراحةً.1
أنواع الانتقالات (Transition types). استدعِ addTransitionType() داخل نفس الـ startTransition لاختيار متغير، مثل اتجاهات تمرير مختلفة للتنقل للأمام وللخلف:
<ViewTransition default={{
'navigation-back': 'slide-right',
'navigation-forward': 'slide-left',
}}>
أحداث JavaScript. تمنحك onEnter، و onExit، و onUpdate، و onShare العناصر الزائفة القديمة/الجديدة حتى تتمكن من استدعاء .animate() مباشرة. قم دائمًا بإرجاع دالة تنظيف (cleanup function) حتى يتمكن المتصفح من إلغاء الحركات المقاطعة.1
هل يعمل ViewTransition مع Next.js و React Router؟
نعم، مع وجود بعض الملاحظات على كلا الجانبين. لدى Next.js تكامل من الدرجة الأولى ولكنه تجريبي: قم بضبط experimental: { viewTransition: true } في ملف next.config.js، وبما أن App Router يشحن نسخة React canary، فإن import { ViewTransition } from 'React' يعمل مباشرة — تنقلات المسارات هي Transitions، لذا يتم تفعيل الحركات عند التنقل تلقائيًا. تضع Vercel علامة "غير موصى به للإنتاج" على هذا الخيار اعتبارًا من وثائق Next.js 16 الحالية.4
يتخذ React Router نهجًا مختلفًا يعمل على النسخة المستقرة من React: خاصية viewTransition على <Link>، و <NavLink>، و <Form> تقوم بتغليف التنقل في document.startViewTransition() مباشرة — دون تدخل مكون React.7 ظهرت لأول مرة كـ unstable_viewTransition في الإصدار v6.17.0 وهي مستقرة في الإصدار v7، إلى جانب خطاف (hook) useViewTransitionState للتنسيق الدقيق. لا تخلط بين النموذجين: إذا كان مكون <ViewTransition> الخاص بـ React نشطًا، فإن React يتوقع أن يمتلك هو استدعاءات startViewTransition.1
الخلاصة
عندما لا يقوم React <ViewTransition> بأي شيء، فغالباً ما يكون السبب هو غلاف الانتقال (transition wrapper)، أو قاعدة الوضع، أو قناة الإصدار، أو المتصفح. قم بإصلاح هذه الأربعة وسيكون الـ API موثوقاً، مع طبقات من فئات CSS، وأنواع الانتقالات، واستدعاءات الأحداث (event callbacks) لإضافة اللمسات النهائية. تعامل معه على حقيقته في عام 2026: ميزة في قناة الكناري (canary-channel) قريبة من مرحلة الإنتاج في Next.js App Router ولا تزال تجريبية في كل مكان آخر. لمزيد من الأدلة العملية، راجع شرحنا لـ ترقيم الصفحات باستخدام المؤشر (cursor pagination) في Postgres مع Node.js لطبقة البيانات خلف تلك القوائم المتحركة، ودليلنا حول عمليات نشر Kubernetes بدون توقف (zero-downtime) لشحن التطبيق دون فقدان أي طلبات.
Footnotes
-
React documentation,
<ViewTransition>reference (Canary) — https://React.dev/reference/React/ViewTransition ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11 ↩12 ↩13 ↩14 ↩15 ↩16 -
web.dev, "Same-document view transitions have become Baseline Newly available" — https://web.dev/blog/same-document-view-transitions-are-now-baseline-newly-available ↩ ↩2 ↩3
-
React Labs, "View Transitions, Activity, and more" (April 23, 2025) — https://React.dev/blog/2025/04/23/React-labs-view-transitions-activity-and-more ↩
-
Next.js documentation,
viewTransitionconfig (updated 2026-05-19) — https://nextjs.org/docs/app/API-reference/config/next-config-js/viewTransition ↩ ↩2 -
Can I use, View Transitions API (single-document) — https://caniuse.com/view-transitions ↩
-
Can I use, View Transitions (cross-document) — https://caniuse.com/cross-document-view-transitions ↩
-
React Router, "View Transitions" how-to — https://reactrouter.com/how-to/view-transitions ↩