الترحيل من React
يقارب Carats React عن قصد، لذا تنتقل معظم شيفرة المكونات مباشرة. والفروق أدناه هي التي تكسر الترحيل فعلًا.
| المفهوم | React | Carats |
|---|---|---|
| بيئة التشغيل | React وReact DOM وDOM افتراضي | JJSX فقط؛ المكونات دوال تُعيد HTML |
| الحالة | useState يُعيد تصيير المكوّن | use يخزّن قيمة؛ وDOM يُحدَّث يدويًا |
| الآثار | useEffect مع مصفوفة اعتماديات | afterMount (بعد التحميل) أو beforeMount (فورًا)، بلا اعتماديات |
| معالجات الأحداث | <button onClick={fn}> | addEventListener داخل استدعاء خطاف |
| التوجيه | موجّه نظام ملفات بتخطيطات ومسارات متداخلة | خريطة defineFacets، تُركَّب باستيراد تخطيط |
| بيانات الخادم | getServerSideProps على الصفحة | دالة خادمية لكل مسار مع غلاف Burnish |
| ترويسة المستند | next/head أو تصدير البيانات الوصفية في الإطار | this.head داخل مكوّن دالة |
| بيانات المكوّن الوصفية | Component.displayName وmemo وcontext | defaultProps على المكوّن؛ بلا context ولا memo |
| التنسيق | CSS-in-JS أو أصناف مساعدة | SASS محدود النطاق يستورد رموز تصميم مشتركة |
| الأنواع | واجهات مُستوردة لكل ملف | واجهات DTO عامة من src/dto |
معالجات الأحداث
نموذج الأحداث هو التغيير الذي يكسر الترحيل أكثر من غيره، لذا يجدر بالدقة في وصفه.
// React
<button onClick={() => setOpen(!open)}>Toggle</button>
<input value={query} onChange={(e) => setQuery(e.target.value)} />
// Carats
import { use, afterMount } from '@carats/hooks';
export default function Toggle() {
const open = use(false);
afterMount(() => {
const button = document.getElementById('toggle');
const stop = open.subscribe((value) => {
button?.setAttribute('aria-expanded', String(value));
});
const onClick = () => open.set(!open.get());
button?.addEventListener('click', onClick);
return () => {
stop();
button?.removeEventListener('click', onClick);
};
});
return <button id="toggle" aria-expanded="false">Toggle</button>;
}
الحالة
يصبح `useState` هو `use`، وكل تصيير كان React سيتولاه يصبح كتابة DOM صريحة. أما الحالة التي كانت محلية لمكوّن فتبقى كما هي في الجوهر: استدعِ `use` في المستوى الأعلى من المكوّن، واقرأها بـ `get`، واكتب بـ `set`.
التوجيه
ينهار موجّه نظام الملفات إلى كائن واحد. يصبح كل مسار مُدخلًا في `defineFacets`، وتصبح التخطيطات المتداخلة استيرادًا صريحًا. ولأن كائن الأوجه مشترك، فالمسار الغائب عنه غائب عن العميل وعن الخادم معًا، وهذا يُزيل فئة كاملة من الأخطاء.
بيانات الخادم
يصبح `getServerSideProps` دالةً خادمية، وتصبح الصفحة مُبرَزة. وتبقى صيغة الدالة بالشكل نفسه: الطلب دخلًا والبيانات خروجًا.
// React / Next.js
export async function getServerSideProps({ params }) {
return { props: { symbol: params.symbol } };
}
// Carats
export default culet<TradeData>('/trade/:symbol', async (req) => {
return { symbol: req.params.symbol.toUpperCase() };
});
// Carats page
export default Burnish<TradeData>(function (data) {
return <h1>{data.symbol}</h1>;
});
ترويسة المستند
يصبح تصدير البيانات الوصفية `this.head`، ويجب أن يكون المكوّن تصريح `function` كي يوجد `this`. ويمكن لمكوّن يكون أصلًا دالة سهم أن يبقى كذلك، على حساب أنه لا يساهم بوسوم head.
التنسيق
لا يوجد نظير لـ CSS-in-JS. يستورد كل مكوّن ملف SASS، ويستورد ذلك الملف `base.sass` من أجل رموز التصميم، وتعيش الرموز في المستوى الأعلى من ورقة الأنماط العامة تلك.
قائمة تدقيق الترحيل
- احذف react وreact-dom وكل اعتمادية تخص React وحدها.
- استبدل سمات الأحداث بـ addEventListener داخل استدعاء afterMount أو beforeMount.
- حوّل كل مسار قائم على ملفات إلى مُدخل في خريطة الأوجه، واستورد تخطيطًا مشتركًا صراحةً.
- انقل أجسام getServerSideProps إلى الدوال الخادمية، وغلِّف الصفحة بـ Burnish.
- انقل useState إلى use، وأضف تحديث DOM اليدوي الذي كان إعادة التصيير يتولاه.
- انقل تصدير head إلى this.head في مكوّن دالة.
- استبدل CSS-in-JS بملفات SASS يستوردها كل مكوّن.