SolidJS رقیبی تازه برای React ؟

این روز ها SolidJS به عنوان یک کتابخانه UI برای ساخت برنامه های وب بسیار سریع و کوچک مورد توجه قرار گرفته است.در نگاه اول، Solid تفاوت چندانی با React ندارد. Solid هم مانند ری اکت از JSX استفاده می کند، دارای یک API است که شبیه به React Hooks عمل می کند . و از همان فلسفه React با جریان داده های یک طرفه، رابط های غیرقابل تغییر و غیره پیروی می کند.اما اجازه ندهید ظاهرقضیه شما را فریب دهد زیرا Solid اساساً متفاوت است. اول از همه، برای به روز رسانی UI از Virtual DOM استفاده نمی کند. در عوض، Solid به پایه های واکنشی متکی است که حالت برنامه را نگه می‌دارند و به طور خودکار وابستگی‌ها را ردیابی می‌کنند، بنابراین وقتی بخشی از داده تغییر می‌کند، بلافاصله و دقیقاً می‌داند چه چیزی باید به‌روزرسانی شود. این سیستم واکنش‌پذیری به Solid اجازه می‌دهد تا به طور مداوم سرعت و حافظه را برای کتابخانه‌های UI در بالاترین معیار قرار دهد.ثانیاً، Solid یک رویکرد پیش از کامپایل را اتخاذ می کند که در آن از یک کامپایلر برای تنظیم نمودار واکنشی و treeshaking برای کاهش اندازه بسته استفاده می کند. به لطف این کامپایلر، برنامه های Solid در مقایسه با سایر کتابخانه های UI ازسایز بسیار کوچکتری برخوردارند.هدف این مقاله کمک به توسعه دهندگان React است تا از دانش موجود خود برای یادگیری اصول SolidJS استفاده کنند.این مقاله موضوعات زیر را پوشش می دهد:تعریف کامپوننت ها حالت کامپوننت چرخه عمر کامپوننت ارتباط کامپوننت Event Handling refs کار با مدیریت خطا ها استفاده مجدد از کد نتیجه گیریتعریف کامپوننت هادر یک برنامه Solid، کامپوننت ها توابعی هستند که عناصر JSX را برمی گردانند. باید بدانید که کامپوننت کلاس پشتیبانی نمی شوند. توجه داشته باشید که کد JSX در توابعی کامپایل می شود که مستقیماً DOM را به روز می کند (زیرا Solid از Virtual DOM استفاده نمی کند). برای جلوگیری از ایجاد مجدد گره های DOM در هر به روز رسانی، Solid چندین کامپوننت برای حلقه های شرطی ارایه می کند که باید به جای if/else و switch و Array.prototype.map استفاده کنیممهم ترین این مولفه ها شامل Show , Switch و For می شوند.نمونه استفاده از Show:<Show when={loggedIn()} fallback={<button ={toggle}>Log in</button>} > <button ={toggle}>Log out</button> </Show>نمونه استفاده از Switch:<Switch fallback={<p>Normal temperature</p>}> <Match when={temp() >= 40}> <p>Too hot</p> </Match> <Match when={temp() <= 10}> <p>Too cold</p> </Match> </Switch>نمونه استفاده از For:<For each={articles()}>{(a, index) => <li>{index() + 1}: {a.title}</li> }</For>به همین ترتیب، برای جلوگیری از ایجاد مجدد children nodes در هر به روز رسانی، باید از children helper استفاده کنید :function MyComponent(props) { const c = children(() => props.children); return ( <div> {c()} </div> ); }وضعیت حالت کامپوننت هابه مانند ری اکت نقطه مقابل useState و useEffect در Solid از signals و effects استفاده می شود:import { createSignal, createEffect } from &quotsolid-js" function App() { const [count, setCount] = createSignal(0); createEffect(() => { console.log(&quotCount: &quot, count()); }); return <button ={() => setCount((c) => c + 1)}>{count}</button>; }اما باید بدانید که signals تفاوت عمده ای با useState hooks دارد. این تفاوت به شرح زیر است:در حالی که شما فقط می توانید useState() را از داخل یک تابع کامپوننت فراخوانی کنید createSignal() از هر جا می تواند فراخوانی شود .از داخل یک تابع جزء یا یک قلاب سفارشی، می توانید آن را فراخوانی کنیداگر در یک کامپوننت فراخوانی شود، سیگنال وضعیت محلی آن کامپوننت را نشان می دهد. در غیر این صورت، سیگنال یک حالت خارجی را نشان می دهد که هر کامپوننت می تواند آن را وارد کرده و از آن برای ارائه رابط کاربری خود استفاده کند.مهمتر از آن، سیگنال‌ها به‌طور خودکار عملکردهایی را که به داده‌های آن بستگی دارند، ردیابی می‌کنند و هر زمان که داده‌ها تغییر می‌کنند، این توابع را فراخوانی می‌کنند. توجه داشته باشید که اولین عنصر در tuple که توسط createSignal() بازگردانده می شود خود داده نیست بلکه تابع getter می باشد.به مانند useEffect در ری اکت CreateEffect() نیز یک افکت جانبی را زمانی که signal که به آن وابسته است تغییری داشته باشد اجرا می کند . با این حال بر خلاف ری ایکت در solid نیاز نیست که لیستی از بسته های وابسته ارایه دهید.چرخه عمر کامپوننتبا React، هر زمان که وضعیت کامپوننت تغییر کند، تابع کامپوننت شما دوباره اجرا می شود. در نقطه مقابل ، توابع کامپوننت Solid هرگز دوباره اجرا نمی شوند. یک کامپوننت فقط یک بار اجرا می شود تا سیگنال ها و افکت های لازم را ایجاد کند (کد JSX در یک افکت نیز کامپایل می شود). پس از آن کامپوننت ناپدید می شود. این بدان معناست که ما مانند React یا کتابخانه های دیگر به چرخه حیات رویداد های Component دسترسی نداریم.با این حال Solid دو رویداد خاص به ما ارایه می کند: onMount و onCleanuponMount به مانند جلوه ویژه ای است که یکبار بعد از اینکه کل رندر به پایان رسید اجرا می شود . بهترین مثالی که می توان زد واکشی اطلاعات بعد از لود صفحه است.import { createSignal, onMount } from &quotsolid-js" function App() { const [data, setData] = createSignal(); onMount(async () => { const res = await fetch(`/path/to/your/api`); setData(await res.json()); }); return (/* JSX to render UI based on data */); }onCleanupمی تواند در داخل یک کامپوننت فرخوانی شود یا در هر scope که بخشی از اجرای همزمان سیستم واکنشی است. onCleanup زمانی که آن scope از بین برود یا دوبارهاجرا شود اجرا می شود .import { createSignal, createEffect, onCleanup } from &quotsolid-js" function App() { const [counting, setCounting] = createSignal(false); const [count, setCount] = createSignal(0); createEffect(() => { if (counting()) { const c = setInterval(() => setCount((val) => val + 1), 300); onCleanup(() => clearInterval(c)); } }); return ( <div> <button type=&quotbutton&quot ={() => setCounting((val) => !val)}> {counting() ? &quotStop&quot : &quotStart&quot} </button> <p>Counter: {count()}</p> </div> ); }ارتباط کامپوننت ها:از این نظر، Solid تقریباً مشابه React است. شما از props برای انتقال داده‌ها از کامپوننت والد به فرزند (یا بازگرداندن اقدامات به والدین) استفاده می‌کنید. از Context API برای ارسال داده به کامپوننت های نزولی استفاده کنید.با این حال، یک هشدار وجود دارد. به طور کلی، شما نباید props را تخریب کنید.با انجام این کار، واکنش پذیری را از دست خواهید داد، به این معنی که UI مؤلفه فرزند با تغییر مقادیر prop به روز نمی شود. برای جبران، Solid دو کمک کننده برای کار با props ارائه می دهد:mergeProps() و splitProps() .// این کار را نکید function Greeting({ name, greeting = &quotHi&quot }) { return <h3>{greeting}, {name}!</h3> } // از mergeProps() برای مقدار دهی اولیه استفاده کنید function Greeting(props) { const merged = mergeProps({ greeting: &quotHi&quot }, props); return <h3>{merged.greeting}, {merged.name}!</h3> }// این کار را نکنید export default function Greeting(props) { const { greeting, name, ...others } = props; return <h3 {...others}>{greeting}, {name}!</h3> } // از splitProps() به جای سینتکس rest استفاده کنید function Greeting(props) { const [local, others] = splitProps(props, [&quotgreeting&quot, &quotname&quot]); return <h3 {...others}>{local.greeting}, {local.name}!</h3> }مقایسه حجم و مدت زمان اسکریپتینگ در ری اکت و Solid jsمدیریت رویداد ها:مانند ری اکت ،Solid فقط از جریان داده های یک طرفه پشتیبانی می کند. هیچ مکانیزم داخلی برای اتصال ورودی وجود ندارد. با این حال، برخلاف React، برنامه‌های Solid به‌جای رویدادهای مصنوعی، مستقیماً از رویدادهای DOM استفاده می‌کنند.function App() { const [name, setName] = createSignal(&quotWorld&quot); return ( <div> <input type=&quottext&quot value={name()} ={(evt) => setName(evt.currentTarget.value)} /> <p>Hello, {name()}!</p> </div> ); }کار با refsاستفاده از refs در Solid تفاوت چندانی با React ندارد. اساسا، شما می توانید یک متغیر محلی را اعلام کرده و آن را به یک prop با نام اختصاص دهید یا از callback استفاده کنید:// local variable function SimpleForm() { let ref; onMount(() => ref.focus()); return (<input ref={ref} />); } // ref callback function SimpleForm() { return ( <input ref={el => { onMount(() => el.focus()) }} /> ); }مدیریت خطا:ایده دیگری که Solid از React گرفته است اجزای مرز خطا است. با این حال، لازم نیست آن را به صورت دستی پیاده سازی کنید چرا که ErrorBoundary یک کامپوننت است که داخل خود solid گنجانده شده.import { ErrorBoundary } from &quotsolid-js" <ErrorBoundary fallback={err => { // report error console.log(err); // fallback UI return (/* JSX */) }}> {/* your component tree */} </ErrorBoundary>استفاده مجدد از کد:در React، شما چندین تکنیک برای استفاده مجدد از کد دارید که محبوب‌ترین آنها کامپوننت‌های مرتبه بالاتر، رندر پروپ‌ها و هوک‌های سفارشی است. می توانید از تکنیک های مشابه با Solid نیز استفاده کنید.نتیجهSolidJS عملکردی باورنکردنی و اندازه باندل بسیار کوچک را ارائه می دهد در حالی که می تواند یک مدل برنامه نویسی ساده را که همه ما دوست داریم حفظ کند.به عنوان یک کتابخانه نسبتا جدید، اکوسیستم Solid هنوز کوچک هستند، اما ممکن است با شناخت بیشتر افراد با پتانسیل های آن تغییر کند.در زمان نگارش این مقاله، مخزن Solid’s GitHub دارای 21 هزار ستاره است و این پروژه توسط شرکت های معتبری مانند Cloudflare، Netlify، Vercel و… پشتیبانی می شوداین مقاله فقط به موضوعات اساسی استفاده از SolidJS پرداخته است. امیدوارم اگر می‌خواهید Solid را امتحان کنید، بتواند در زمان شما صرفه‌جویی کند.