آموزش ساخت hook های شخصی در کتابخانه ی React

ساخت هوک (hook) در React

تاریخ انتشار: ۱۰ ماه پیش

آخرین ویرایش: ۱۰ ماه پیش

سطح مقاله: متوسط

دسته:React

بازدید: ...

مشاهده ی عناوین مهم این مقاله ساختار و سرتیتر های مقاله:

پیش نیاز

برای مطالعه ی این مقاله باید با جاوا اسکریپت و همچنین react.js آشنایی حداقلی داشته باشین.

برای شروع کار باید اول با hook ها (مثل «نوک» تلفظ میشه نه مثل «خوک») آشنا بشین و بدونین اصلا چرا ساخته شدن. به زبون ساده میشه گفت هوک ها فقط یک سری توابع هستن که به شما قابلیت استفاده ی مجدد و ساده از یک منطق خاص رو میدن تا نیازی به نوشتن کد های پیچیده وسط کامپوننت هاتون نباشه. فایده ی اصلیشون هم استفاده از state و side-effect ها در کدهاتونه.

اگه از بازاریای قدیم react باشین می دونین که قدیما اکثر برنامه نویس های react از class component یا کامپوننت های کلاس محور (یا هر چی دوست دارین اسمش رو بزارین) استفاده می کردن اما کار با کلاس ها برای خیلی ها جذاب نیست و خیلی از برنامه نویس ها باهاش حال نمی کنن. اون موقع کامپوننت های تابع محور (functional component) هم وجود داشتن اما قابلیت نگهداری state نداشتن بنابراین به بعضی از قابلیت های کلاس ها دسترسی نداشتن. مثلا کلاس ها lifecycle method ها رو داشتن که به شما اجازه می دادن در مواقع خاص از چرخه ی عمر یک کامپوننت (مثلا موقع mount شدن یا سوار شدنش روی DOM یا موقع حذف شدنش از DOM و غیره) عملیات خاصی رو انجام بدین. کامپوننت های تابع محور به هیچ قابلیتی که به state وابسته بود دسترسی نداشتن واسه همین معمولا ازشون استفاده نمی شد مگه اینکه برنامتون خیلی ساده بود و اصلا نیازی به این قابلیت های اضافی وجود نداشت.

اینا گذشت تا اینکه توی نسخه ی 16.8 از react قابلیت جدیدی به اسم هوک ها (hooks) اضافه شدن که به شما اجازه می دادن قابلیت های کامپوننت های کلاس محور مثل همین lifecycle method ها رو توی کامپوننت های تابع محور هم داشته باشین! از اون تاریخ به بعد (حدودا اوایل سال ۲۰۱۹) کم کم به محبوبیت کامپوننت های تابع محور اضافه شد و در حال حاضر اکثر قریب به اتفاق برنامه نویس های react از این کامپوننت ها استفاده می کنن.

تعداد هوک ها توی کتابخونه ی react خیلی کمه و بیشتر از انگشت های دستاتون نیست اما خیلی اوقات آدم آرزو می کرد که یک هوک هم برای فلان کار داشتیم برای همین تیم react به برنامه نویس های react اجازه میده هوک های شخصی خودشون رو تعریف کنن که بهشون custom hook یا هوک های سفارشی میگن. من اول این مقاله گفتم که هوک ها در اصل یه سری تابع هستن که قابلیت های خاصی به شما می دن اما اصلا فرقی هم با توابع عادی دارن؟ بله! فرق هوک ها با توابع معمولی توی دو تا مورد خاصه.

همه ی هوک های react، چه اونایی که توی خود کتابخونه ی react هست و چه اونایی که شما بخواین بنویسین، باید از پیشوند use توی اسمشون استفاده کرده باشن. اگه دقت کرده باشین هم خود هوک های react از همین قانون پیروی می کنن (useState و useEffect و useMemo و ...). با این حساب اگه قرار باشه یک هوک سفارشی بنویسیم، توی انتخاب اسمش آزادیم اما باید با use شروع بشه.

طبیعت هوک های سفارشی به هوک های دیگه وابسته است! همه ی هوک های سفارشی ما یا باید از یه هوک سفارشی دیگه یا از هوک های خود react استفاده کنن! به عبارت دیگه هر هوک سفارشی خودش ترکیبی از یک یا چند هوک دیگه است. با این حساب اگه هوک سفارشی شما از هیچ هوک دیگه ای استفاده نکنه اصلا هوک سفارشی یا غیر سفارشی یا مجلسی یا هیچی دیگه نیست، به قول باشگاهی جماعت دارین اشتباه میزنین و فقط یک تابع ساده ساختین، همین!

دیگه وراجی بسه و موقع کد نویسیه! اول با یک مثال خیلی ساده شروع می کنیم.

ما میخوایم یه سیستم طراحی کنیم که با فعال شدنش یه موشک به سمت ماه شلیک میشه اما قابلیت اینو داره که سریعا ماموریتش رو لغو کنه و به آشیانه برگرده. شما این سیستم رو طراحی کنین، منم دکمه ی فعال شدنش رو طراحی می کنم که تقسیم کار کرده باشیم:

import { useState } from "react";

const ShuttleButton = () => {
const [toMoon, setToMoon] = useState(false);

return (
<div>
<button onClick={() => setToMoon(!toMoon)}>
{toMoon ? "برو به ماه" : "برگرد به زمین"}
</button>
<p>{toMoon ? "در حال برگشت به زمین" : "در حال سفر به ماه"}</p>
</div>
);
};

export default ShuttleButton;

این یه کد ساده است که فقط یه دکمه داره. متن داخل این دکمه به شما میگه سفینه ی ما باید به ماه بره یا به زمین برگرده و متن داخل پاراگراف هم وضعیت فعلی رو شرح میده که آیا سفینه در حال سفر به ماه هست یا داره برمیگرده. وقتی روی دکمه ی ما کلیک بشه، state این کامپوننت (toMoon) برعکس حالت عادی خودش میشه. 

ما می تونیم این منطق رو به شکل یه هوک ساده بسازیم. یادتون باشه که دو تا قانون داشتیم: اسمش باید با use شروع بشه و خودش هم باید از یه هوک استفاده کنه:

const useShuttle = (initialPath: boolean = false): [boolean, () => void] => {
const [toMoon, setToMoon] = useState(initialPath);

const changePath = () => {
setToMoon(!toMoon);
};

return [toMoon, changePath];
};

همونطور که می بینین اولا اسمش با use شروع میشه (shuttle اسم دلخواه منه که یعنی «شاتل» یا همون سفینه). یه مقدار پیش فرض و اولیه هم می گیریم که وضعیت اول سفینه رو مشخص می کنه: آیا از همون اول در حال سفر به ماه باشه یا زمین؟ من false رو براش گذاشتم که یعنی از اول در حال سفر به ماهه اما موقع صدا زدنش می تونیم تغییرش بدیم. در ضمن می بینین که داریم از هوک useState داخلش استفاده می کنیم که یکی از شرط ها بود. در نهایت باید یه مقداری رو برگردونیم که بستگی به نوع هوک نوشته شده داره. مثلا بعضی هوک ها فقط یک عدد برمیگردونن اما بعضی هوک ها یه مقدار رو به همراه یه متد برای تغییرش برمیگردونن. کلا آرایه ها در این مواقع بهترن چون میتونیم از array destructuring استفاده کنیم و هر اسمی رو برای مقادیر برگردونده شده انتخاب کنیم:

import { useState } from "react";

const useShuttle = (initialPath: boolean = false): [boolean, () => void] => {
const [toMoon, setToMoon] = useState(initialPath);

const changePath = () => {
setToMoon(!toMoon);
};

return [toMoon, changePath];
};

const ShuttleButton = () => {
const [path, changePath] = useShuttle();

return (
<div>
<button onClick={() => changePath()}>
{path ? "برو به ماه" : "برگرد به زمین"}
</button>
<p>{path ? "در حال برگشت به زمین" : "در حال سفر به ماه"}</p>
</div>
);
};

export default ShuttleButton;

می بینین که من هوک useShuttle رو صدا زدم و مقادیر برگردونده شده رو هم destructure کردم. شما می تونین هر اسمی به جای path و changePath بزارین (اصلا مهم نیست و نیازی نیست با اسم های داخل هوک همخونی داشته باشن). تبریک میگم شما اولین هوک سفارشیتون رو نوشتین! ما شاء الله!

هوکی که نوشتیم واقعی بود اما علمی تخیلی بود! یعنی استفاده ی واقعی نداشت. بهتره یه هوکی بنویسیم که واقعا به درد برنامه نویسی وب بخوره. مثلا خیلی اوقات نیازه که بدونیم دقیقا اندازه ی پنجره ی مرورگر (window size) کاربر چقدر هست و اگر تغییر کرد سریعا مقدارش برامون به روز رسانی بشه.

import { useState, useEffect } from "react";

function useWindowSize() {
const [windowSize, setWindowSize] = useState({
width: window.innerWidth,
height: window.innerHeight,
});

useEffect(() => {
function handleResize() {
setWindowSize({
width: window.innerWidth,
height: window.innerHeight,
});
}

window.addEventListener("resize", handleResize);

return () => {
window.removeEventListener("resize", handleResize);
};
}, []);

return windowSize;
}

const AppComponent = () => {
const windowSize = useWindowSize();

return (
<div>
<p>{windowSize.width}</p>
<p>{windowSize.height}</p>
</div>
);
};

export default AppComponent;

اولین قدم اینه که از useState استفاده کنیم تا بشه مقدار طول و عرض پنجره ی مرورگر کاربر رو یه جایی ذخیره داشته باشیم. بعدش از یه useEffect استفاده کردیم (میدونین که عملیات هایی مثل Event Listener ها همشون side effect حساب میشن پس باید داخل useEffect باشن). داخل این useEffect یه Event Listener داریم که به تغییر اندازه ی پنجره ی مرورگر حساسه و اندازه ی جدید رو بهمون میده. ما هم اون رو روی state خودمون تنظیم می کنیم. مرحله ی بعدی هم بهش cleanup یا تمیزکاری می گن که باید Event Listener ساخته شده رو حذف کنیم (removeEventListener).

نکته ی مهم

نکــــــته!

داخل useEffect اجازه دارین یک تابع رو return کنین که بهش cleanup function میگن. این تابع برگردونده شده فقط توی دو موقعیت اجرا میشه: ۱- موقع unmount شدن کامپوننت (حذف شدنش) و ۲- موقع رندر دوباره یا اجرای دوباره ی useEffect. وظیفه ی اصلی این تابع حذف مقادیری هستن که بعد از حذف این کامپوننت باید پاک بشن. مثلا event listener ها رو در مثال بالا به همین شکل حذف کردیم چون اگر حذف نکنیم روی هم تلنبار میشن و مموری لیک خواهیم داشت! یعنی پشت سر هم event listener می سازین اما حذف نمی کنین و اینا داخل مموری کاربر روی هم جمع میشن تا بی نهایت که بهش نشت حافظه یا مموری لیک یا memory leak می گیم.

در نهایت هم طول و عرض رو داخل دو تا تگ <p> داخل مرورگر نمایش می دیم. اگه بخواین می تونین این کد رو اجرا کنین و پنجره ی مرورگرتون رو بزرگ و کوچیک کنین تا ببینین این اعداد در لحظه تغییر می کنن.

شاید از این مقالات نیز خوشتان بیاید:

sample

معرفی مقدماتی HTMX

HTMX چیست؟ بازم یه فریم ورک جاوا اسکریپتی دیگه؟! بله اما قول می دم این یکی دیگه فرق داره! در واقع HTMX یه فریم ورک جاوا اسکریپتیه که می خواد سر به تن جاوا اسکریپت نباشه! یه چیزی مقابل react و ادا اصول هاش! در این مقاله با هم با HTMX آشنا می شیم و می بینیم که نقاط قوت و ضعفش کجاست، جامعه ی آماریش چطوره و آیا میشه...

sample

نصب و پیکربندی مقدماتی Nginx

Nginx یکی از مشهور ترین وب سرور ها و همچنین reverse proxy server ها در دنیای وب حساب میشه و اگر بخواین خودتون اون رو روی سرورتون تنظیم کنین باید بدونین که یکم دنگ و فنگ داره و دانش فنی می خواد. این مقاله به شما یاد میده چطور Nginx رو برای سرور سایت خودتون نصب و پیکربندی کنین تا یکم تجربه ی DevOps هم داشته باشیم دیگه!