این روز ها SolidJS به عنوان یک کتابخانه UI برای ساخت برنامه های وب بسیار سریع و کوچک مورد توجه قرار گرفته است.
در نگاه اول، Solid تفاوت چندانی با React ندارد. Solid هم مانند ری اکت از JSX استفاده می کند، دارای یک API است که شبیه به React Hooks عمل می کند . و از همان فلسفه React با جریان داده های یک طرفه، رابط های غیرقابل تغییر و غیره پیروی می کند.
اما اجازه ندهید ظاهرقضیه شما را فریب دهد زیرا Solid اساساً متفاوت است. اول از همه، برای به روز رسانی UI از Virtual DOM استفاده نمی کند. در عوض، Solid به پایه های واکنشی متکی است که حالت برنامه را نگه میدارند و به طور خودکار وابستگیها را ردیابی میکنند، بنابراین وقتی بخشی از داده تغییر میکند، بلافاصله و دقیقاً میداند چه چیزی باید بهروزرسانی شود. این سیستم واکنشپذیری به Solid اجازه میدهد تا به طور مداوم سرعت و حافظه را برای کتابخانههای UI در بالاترین معیار قرار دهد.
ثانیاً، Solid یک رویکرد پیش از کامپایل را اتخاذ می کند که در آن از یک کامپایلر برای تنظیم نمودار واکنشی و treeshaking برای کاهش اندازه بسته استفاده می کند. به لطف این کامپایلر، برنامه های Solid در مقایسه با سایر کتابخانه های UI ازسایز بسیار کوچکتری برخوردارند.
هدف این مقاله کمک به توسعه دهندگان React است تا از دانش موجود خود برای یادگیری اصول SolidJS استفاده کنند.
این مقاله موضوعات زیر را پوشش می دهد:
تعریف کامپوننت هاحالت کامپوننت چرخه عمر کامپوننتارتباط کامپوننتEvent Handlingrefs کار با مدیریت خطا هااستفاده مجدد از کدنتیجه گیری
تعریف کامپوننت ها
در یک برنامه Solid، کامپوننت ها توابعی هستند که عناصر JSX را برمی گردانند. باید بدانید که کامپوننت کلاس پشتیبانی نمی شوند. توجه داشته باشید که کد JSX در توابعی کامپایل می شود که مستقیماً DOM را به روز می کند (زیرا Solid از Virtual DOM استفاده نمی کند). برای جلوگیری از ایجاد مجدد گره های DOM در هر به روز رسانی، Solid چندین کامپوننت برای حلقه های شرطی ارایه می کند که باید به جای if/else و switch و Array.prototype.map استفاده کنیم
مهم ترین این مولفه ها شامل Show , Switch و For می شوند.
نمونه استفاده از Show:
<Show
when={loggedIn()}
fallback={<button onClick={toggle}>Log in</button>}
> <button onClick={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 "solid-js";
function App() {
const [count, setCount] = createSignal(0);
createEffect(() => {
console.log("Count: ", count());
});
return <button onClick={() => 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 و onCleanup
onMount به مانند جلوه ویژه ای است که یکبار بعد از اینکه کل رندر به پایان رسید اجرا می شود . بهترین مثالی که می توان زد واکشی اطلاعات بعد از لود صفحه است.
import { createSignal, onMount } from "solid-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 "solid-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="button" onClick={() => setCounting((val) => !val)}>
{counting() ? "Stop" : "Start"}
</button>
<p>Counter: {count()}</p>
</div>
);
}
ارتباط کامپوننت ها:
از این نظر، Solid تقریباً مشابه React است. شما از props برای انتقال دادهها از کامپوننت والد به فرزند (یا بازگرداندن اقدامات به والدین) استفاده میکنید. از Context API برای ارسال داده به کامپوننت های نزولی استفاده کنید.
با این حال، یک هشدار وجود دارد. به طور کلی، شما نباید props را تخریب کنید.
با انجام این کار، واکنش پذیری را از دست خواهید داد، به این معنی که UI مؤلفه فرزند با تغییر مقادیر prop به روز نمی شود. برای جبران، Solid دو کمک کننده برای کار با props ارائه می دهد:mergeProps() و splitProps() .
// این کار را نکید
function Greeting({ name, greeting = "Hi" }) {
return <h3>{greeting}, {name}!</h3>}
// از mergeProps() برای مقدار دهی اولیه استفاده کنید
function Greeting(props) {
const merged = mergeProps({ greeting: "Hi" }, 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, ["greeting", "name"]);
return <h3 {...others}>{local.greeting}, {local.name}!</h3>}
مدیریت رویداد ها:
مانند ری اکت ،Solid فقط از جریان داده های یک طرفه پشتیبانی می کند. هیچ مکانیزم داخلی برای اتصال ورودی وجود ندارد. با این حال، برخلاف React، برنامههای Solid بهجای رویدادهای مصنوعی، مستقیماً از رویدادهای DOM استفاده میکنند.
function App() {
const [name, setName] = createSignal("World");
return (
<div>
<input
type="text"
value={name()}
onInput={(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 "solid-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 را امتحان کنید، بتواند در زمان شما صرفهجویی کند.