يأتي SolidJS 2.0 مع نموذج بيانات غير متزامن (async-data) أصلي يتيح للمكون التعامل مع الـ promise كأي قيمة تفاعلية أخرى، ويقوم بذلك دون سلسلة عمليات إعادة الصيرورة (re-renders) التي يواجهها مطورو React عند استخدام Suspense والـ hooks. هذا التغيير مهم لأنه يحافظ على واجهة المستخدم (UI) معروضة على الشاشة أثناء تحديث البيانات، ويقلل من الأكواد الروتينية (boilerplate)، ويوفر مساراً ملموساً لفرق React لنقل أكواد جلب البيانات الخاصة بهم إلى Solid.
لماذا يبدو نموذج Solid غير المتزامن مختلفاً
في React، المكون الذي يحتاج إلى بيانات عادة ما يستدعي hook (غالباً ما يكون مخصصاً) يعيد كائناً يشبه الـ promise، ثم يغلف واجهة المستخدم بـ <Suspense> لإظهار محتوى بديل (fallback) أثناء اكتمال الـ promise. في كل مرة تستقر فيها الـ promise، يقوم React بجدولة عملية إعادة صيرورة؛ وإذا قام نفس المكون بإعادة جلب البيانات لاحقاً، فقد يظهر المحتوى البديل بشكل خاطف فوق المحتوى المرئي بالفعل.
Solid يقلب الموازين. الـ promise هو ببساطة قيمة يراقبها الرسم البياني التفاعلي (reactive graph). عندما تقرأ عملية حسابية تلك القيمة، يقوم الرسم البياني بإيقاف تلك القراءة مؤقتاً حتى تكتمل الـ promise، ولكن تظل بقية واجهة المستخدم معروضة. في المرة الأولى التي يتم فيها تحميل المكون (mount)، يمكن لحدود <Loading> عرض محتوى بديل؛ بعد ذلك، فإن إعادة جلب البيانات تترك الـ DOM الحالي دون تغيير حتى تصل البيانات الجديدة. لا حاجة لاستخدام "await" صريح داخل المكون، ولا createResource، ولا تبديل يدوي للحالة (state).
اللبنات الأساسية
- حدود
<Loading>– تستبدل<Suspense>في React. تعرض محتوى بديلاً فقط عند التحميل الأولي. بعد عملية الرسم الأولى (first paint)، لا تحل القراءة المعلقة محل واجهة المستخدم؛ بل يظل المحتوى القديم موجوداً حتى تكتمل القيمة الجديدة. يمكنك تمرير خاصيةonلفرض ظهور مؤشر تحميل (spinner) عند إعادة جلب محددة. - مكون
<Reveal>– يتحكم في كيفية ظهور حدود<Loading>المتعددة معاً. يمكنك الاختيار بين:- Sequential (تسلسلي): تظهر الحدود واحداً تلو الآخر حسب ترتيبها في الـ DOM.
- Together (معاً): تظهر جميعها في وقت واحد عندما تكون كل قطعة بيانات جاهزة.
- Natural (طبيعي): يظهر كل مكون بمجرد وصول بياناته الخاصة.
- إشارة
isPending– تعيدtrueأثناء وجود عملية قراءة قيد التنفيذ. استخدمها لوضع شريط تحميل رفيع أو رسوم متحركة بسيطة بينما يظل المحتوى الرئيسي مرئياً، مما يمنحك ميزة "stale-while-revalidate" مجاناً. - مولد
action– يستبدل تحديثات الحالة القابلة للتغيير (mutable-state) في React. يمكن لـaction(function*…)تحديث واجهة المستخدم بشكل تفاؤلي (optimistically)، ثم استخدامyieldلانتظار رد الخادم، وبعد ذلك تسوية (reconcile) النتيجة عند اكتمال الـ promise. تبدو واجهة المستخدم فورية، وخطوة التسوية مدمجة في هذه اللبنة الأساسية.
كيفية مطابقة هذه العناصر مع مفاهيم React
| الميزة | نهج React | نهج Solid 2.0 |
|---|---|---|
| جلب البيانات | use() (تجريبي) أو hooks خارجية؛ النتيجة مغلفة بـ <Suspense> |
createMemo (أو ما يشابهها) تعيد promise؛ القراءة مباشرة في JSX |
| واجهة تحميل البيانات | قد يعيد <Suspense> تفعيل المحتوى البديل عند كل إعادة جلب |
<Loading> يعمل فقط عند التحميل الأول؛ إعادة الجلب تحافظ على الواجهة القديمة |
| التحديث (Refreshing) | useTransition لتأجيل تحديثات واجهة المستخدم |
إشارات isPending تشير إلى القراءات المعلقة دون تبديل واجهة المستخدم |
| التعديلات (Mutations) | useState/useReducer + استدعاءات async، غالباً ما تكون مغلفة في actions مخصصة |
action(function*…) مع معالجة تفاؤلية مدمجة |
النتيجة العملية هي أن Solid يبني ما يعامله React كـ hooks منفصلة داخل محرك التفاعلية الأساسي.
دليل الهجرة خطوة بخطوة
- تحديد مصدر البيانات – في React، من المحتمل أن يكون لديك
const data = useMyFetch(url). في Solid، استبدل ذلك بـ memo يعيد الـ promise:const data = createMemo(() => fetch(url).then(r => r.json())). - تغليف المكون الأساسي – إذا كان المكون يتم عرضه قبل اكتمال الـ promise، فقم بإحاطته بـ
<Loading fallback={<Spinner/>}>…</Loading>. يظهر الـ fallback فقط عند أول عملية mount. - استبدال مؤشرات التحميل الخاصة بكل عملية إعادة جلب – حيث كنت تقوم سابقاً بتبديل flag التحميل، اقرأ الآن
isPending(data). استخدم هذه القيمة المنطقية (boolean) لعرض مؤشر بسيط بينما تظل واجهة المستخدم الحالية على الشاشة. - تحويل التحديثات المتفائلة (optimistic updates) – إذا كان لديك
setState(prev => ({...prev, optimisticValue}))متبوعاً باستدعاء async، فأعد كتابتها كـconst update = action(function* (newValue) { state = newValue; const server = yield fetch(...); state = reconcile(server); });. يقوم الـ generator بتسليم التحكم حتى يستجيب الخادم، ثم يقوم بتحديث الرسم البياني التفاعلي (reactive graph) تلقائياً. - التعامل مع أجزاء async متعددة – قم بتداخل حدود
<Loading>حسب الحاجة، ثم أضف غلاف<Reveal>لتحديد ما إذا كانت ستظهر معاً أو واحداً تلو الآخر. هذا يستبدل الأنماط التي كان مطورو React يستخدمون فيها مكونات<Suspense>متعددة بشكل متتابع مع فحوصات حالة (state checks) معقدة. - اختبار التدفق – نظرًا لأن Solid لا يعيد عملية الـ re-render عند اكتمال الـ promise، تحقق من أن تحديثات واجهة المستخدم لا تزال تحدث حيث تتوقعها. يقوم الرسم البياني التفاعلي بنشر التغييرات تلقائياً؛ ولا داعي لاستدعاءات
useEffectإضافية.
ما لا يزال قيد التغيير
واجهة برمجة تطبيقات (API) الـ async في Solid 2.0 لا تزال حالياً في المرحلة التجريبية (beta). قد تتغير أسماء مثل <Loading> و action قبل الإصدار المستقر، ولا تزال الوثائق في طور التطور. الفكرة الأساسية — معاملة الـ promises كقيم تفاعلية (reactive values) — تظل دون تغيير، ولكن يجب على المستخدمين الأوائل توقع تغييرات جذرية (breaking changes) طفيفة مع استقرار المكتبة.
من المستفيد؟
- فرق React التي تعتمد بكثافة على جلب البيانات – تقليل الحاجة إلى مكتبات الحالة الخارجية ونمط stale-while-revalidate المدمج يمكن أن يقلل من حجم الحزمة (bundle size) ويبسط قواعد الكود (codebases).
- التطبيقات التي تركز على الأداء – من خلال تجنب إعادة الرندرة (re-render) الكاملة للمكون عند كل عملية جلب، يوفر Solid تحديثات مرئية أكثر سلاسة، خاصة على الأجهزة الضعيفة.
- المطورون الذين سئموا من "وميض مؤشر التحميل" (flash of spinner) – سلوك "التحميل الأول فقط" لحدود
<Loading>يقضي على الإزعاج الشائع المتمثل في وميض مؤشر التحميل فوق المحتوى المرئي بالفعل.
العيوب المحتملة
- حالة الـ beta – حتى تستقر الـ API، قد تحتاج المشاريع طويلة الأمد إلى تخصيص ميزانية لجهود الانتقال (migration) لاحقاً.
ما يجب مراقبته لاحقاً
تابع سجل التغييرات (changelog) الرسمي لأي إعادة تسمية لـ <Loading> أو action.
الخلاصة: يتيح لك SolidJS 2.0 معاملة الـ promises كقيم تفاعلية من الدرجة الأولى، مما يحافظ على استقرار واجهة المستخدم أثناء تحديث البيانات ويزيل الحاجة إلى مجموعة من الـ hooks بأسلوب React. بالنسبة للفرق المستعدة للانتقال إلى ما وراء نموذج "التركيز على إعادة الرندرة" (re-render-centric model)، فإن مسار الانتقال واضح، ومزايا الأداء ملموسة، والخطر الحقيقي الوحيد هو عدم اليقين المعتاد في مرحلة الـ beta.
