برنامه نویس وب و فرانتاند و ریاکت و وب سایت https://react.ir
خداحافظ ریداکس، سلام کانتکست (قسمت اول)
تو این مقاله یاد میگیرم که ابزارهای قدیمی رو دور بریزیم و به ابزارهای مدرن و جدید (و صد البته هزاران بار ساده تر) روی بیاریم. (اگر از گوشی موبایل دارید این مقاله میخونید و لینک رو از تلگرام باز کردید، مطمئن بشید که تو حالت instant view نیستید چون قسمتهایی از مقاله تو اون حالت نمایش داده نمیشه)
پیشنهاد میکنم که اول این مقاله رو مطالعه کنید تا متوجه بشید چرا ما به ریداکس نیاز داشتیم:
همونطوری که داخل مقاله بالا بهش اشاره کردم، ما برای ذخیره و جابهجا کردن اطلاعات بین کامپوننتها به ابزار Global state management نیاز داریم. تو اکو سیستم ریاکت برنامه نویسا معمولا از ابزاری به نام ریداکس استفاده میکنن تا اطلاعات رو بین کامپوننتها جابهجا کنن.
یادگیری ریداکس خیلی سخته، از طرفی خیلی خیلی خیلی پیچیده هستش. خیلیییییی
چی شد که همه رو آوردن به ریداکس
ما از روز اول کانتکست رو نیاز داشتیم ولی چون تو نسخههای اولیه ریاکت کلا کانتکست نبود و بعدشم Legacy Context اومد که خیلی سخت و عجیب قریب بود پس همه رفتن سمت Global State Management ها.
بعدا که نسخه ۱۶.۳ ریاکت اومد کانتکست معرفی شد ولی امکانات کافی نداشت که جایگزین Global State Management ها بشه و دوباره این سنت دیرینه که هر پروژه ریاکت حتما باید ریداکس داشته باشه با ما برنامه نویسای ریاکت موند. قبل از اینکه ادامه تاریخچه کانتکست رو بگم، نیازه یه معرفی اولیه داشته باشیم که با نحوه استفاده از کانتکس هم آشنا بشید.
خب کار با کانتکس خیلی ساده هستش، چون کانتکست هیچ چیز جدیدی نیست به جز استیت یه کامپوننت دیگه. شما فقط کافیه با ریاکت آشنا باشید تا بتونید کانتکست رو تو ۵ دقیقه یادبگیرید.
به صورت کلی کانتکست که یه جور تونل هستش که میشه اطلاعات رو با اون بین کامپوننتها جابهجا کرد و هروقت دیتا موجود داخل Provider عوض بشه کامپوننتهای متصل به اون تونل دوباره رندر میشن ...
خب این Provider که بالا اسمشو آوردیم چی هستش و از کجا میاد؟
برای دسترسی به Provider کافیه متد createContext رو صدا بزنید تا یک شی Context داشته باشید
کامپوننت Provider که بالا درباره اون صحبت کردیم داخل آبجکت MyContext هستش، این کامپوننت یه پراپرتی (همون prop) داره به نام value که باید مقدار دهی بشه. هر مقداری داخل value بزارید به تمام کامپوننتهایی که به این کانتکس وصل هستن ارسال میشه
تو مثال بالا ما یه کامپوننت ساختیم به نام FelanProvider (اسم کامپوننت زیاد مهم نیست که چی باشه ولی خب واسه خوانا بودن کد بهتره آخرش با Provider تموم بشه)، اگر دقت کرده باشید داخل متد رندر ما MyContext.Provider رو رندر کردیم و مقدار count که داخل استیت بود رو داخل پراپ value اون قرار دادیم. این یعنی الان داخل Context ما عدد ۰ هستش (چون مقدار اولیه استیت ما ۰ هستش).
خب حالا از فاز کانتکست بیایم بیرون، اگر با ریاکت آشنا باشید میدونید که ما واسه عوض کردن استیت تو ریاکت از متد setState استفاده میکنیم. یعنی اگر بخوایم مقدار اون count رو عوض کنیم نیازه که setState رو با مقادیر جدیدا صدا بزنیم. مثلا:
this.setState({ count: 2 })
حالا اگر کامپوننتهایی که به این کانتکست متصل هستن بخوان استیت کانتکست رو عوض کنن باید چیکار کنن ؟ خب با حرفایی که ۲ خط بالاتر زدیم معلوم شد که باید setState بکنیم، ولی کدوم setState ؟ اون کامپوننت که به کانتکست وصل هستش استیت خودشو داره و setState خودشم داره پس اونو نباید صدا بزنیم !
واسه همین میایم متد setState کامپوننت FelanProvider رو هم داخل کانتکس قرار میدیم.
بدترین روش برای قرار دادن setState داخل کانتکست :
روش جایگزین :
بهترین روش:
داخل مثال بالا ما ۲ تا کانتکس ساختیم، داخل اولی setState رو گذاشتیم و داخل دومی state رو قرار دادیم. این روش خیلی optimize هستش (پایین تر توضیح میدم درباره این موضوع)
معادل کد بالا رو بخوایم با فانکشن کامپوننت و هوک بنویسیم میشه:
اگر با هوک آشنایی ندارید مقاله و آموزش ویدیویی من درباره هوک رو از لینک زیر دریافت کنید:
برگردیم به تاریخچه ...
گفتم که تو نسخه ۱۶.۳ کانتکست امکانات کافی رو نداشت! منظورم چی بود؟ خب ما تا اینجا فقط اطلاعات رو داخل تونل قرار دادیم، برای خوندن اطلاعات بیاید ۲ تا کار کنیم.
اول اینکه کامپوننت FelanProvider رو باید یه جایی رندر کنیم (ترجیحا یه جایی بالای درخت ریاکت باشه همونجایی که Provider ریداکس رو رندر میکردید):
واسه اینکه به دیتای Provider دسترسی پیدا کنیم کافیه که Context رو ایمپورت کنیم و اونو رندر کنیم:
مشکل این نسخه از ریاکت و کانتکست اینکه شما داخل لایف سایکلها به دیتای کانتکست دسترسی ندارید (البته یه راه هستش به نام Higher Order Component گذاشتن ولی یکم کثیف کاری داره) و اینم بگم تو اون زمان اصلا هوک وجود نداشت پس فانکشن کامپوننتها زیاد مشکلی نداشتن.
اگر با HOC آشنایی ندارید پیشنهاد میکنم مقاله زیر رو بخونید: (البته با اومدن هوکها موارد استفاده از HOC خیلی کم شده و دیگه استفاده نمیشه ازشون)
تا اینجا شما یاد گرفتید که چهطوری کانتکست رو راه اندازی کنید ولی خب استفاده از کانتکست اونقدرم دلنشین نبود (چی بود اون consumer گذاشتن و render prop کردن، حال آدم بد میشد اصلا)
خلاصه چند وقت از منتشر شدن نسخه ۱۶.۳ گذشت و رسیدیم به نسخه ۱۶.۶، تو این نسخه شما با استفاده از static contextType میتونستید به اطلاعات کانتکست راحت تر دسترسی پیدا کنید
خب نسبت به نسخه قبلی خیلی بهتر شد و میشه به کانتکس مثل استیت یا پراپ رفتار کرد (حتی داخل لایف سایکل هم بهش دسترسی دارید) ولی متاسفانه فقط میشه یک کانتکس رو به این کامپوننت متصل کرد و این چیزی نیست که بشه باهاش کنار اومد چون تو پروژههای واقعی (منظورم اینکه تو مثال میشه یه جوری سر و تهش رو هم آورد ولی تو واقعیت نمیشه) به مشکل میخوریم...
ریاکت ۱۶.۸ و ظهور هوک (Hook)
قبل از هرچیزی باید بگم اگر نمیدونید هوک چهطوری کار میکنه حتما ویدیو آموزش و مقاله من رو درباره هوکهارو مطالعه کنید:
const data = React.useContext(CONTEXT_OBJECT)
داخل اون ویدیو درباره کاستوم هوک صحبت کردم پس دیگه اینجا توضیح زیادی درباره کاستوم هوک نمیدم. کاستوم هوکها همون فانکشنهایی هستن که همیشه ازشون استفاده میکردیم ولی داخلشون از هوکهای ریاکت استفاده میکنیم پس باید قوانین هوکها رو رعایت کنن، از طرفی به صورت قرار دادی واسه راحت بودن تشخیص کاستوم هوکها از فانکشنها پیشنهاد میشه نام کاستوم هوکها با use شروع بشه، برای مثال بالا میشه نام useFelan رو به عنوان نام کاستوم هوک قرار داد.
import React from "react"
import { MyContext } from "../Providers/FleanProvider"
function useFelan() {
return React.useContext(MyContext)
}
export default useFelan
حالا شما حالتی رو در نظر بگیرید که یک کانتکست برای ذخیره کردن اطلاعات کاربر داشته باشید به نام UserProvider و نام کاستوم هوک اون رو useUser قرار داده باشید. (و یا سبدخرید که میشه CartProvider و useCart) و دسترسی به اون خیلی راحت هستش فقط کافیه هوک رو ایمپورت کنید و فراخوانی کنید.
برای مثال کامپوننت Private Route که برای React Router نوشتید به صورت زیر پیاده سازی میشه:
اگر آموزش React Router رو نیاز دارید پیشنهاد میکنم دوره رایگان آموزش React Router 5 من رو ببینید.
فکر نکنم کسی تو ایران باشه که از خوبیهای ماشین پیکان حرفی نزنه :)
پیکان با این که ماشین خوبی بود کولر نداشت و با گذشت زمان قدیمی شد و از رده خارج شد، و جای پیکان رو ماشینهای دیگه گرفتن
اگر نسخههای قدیمی ریاکت رو همون پیکان درنظر بگیریم و ریداکس رو به عنوان کولر، تا الان ما داشتیم یه همچین کاری میکردیم =)
و الان که من این مقاله رو مینویسم تمام ماشینهایی که به بازار میان کولر دارن پس دیگه کسی نمیاد کولر آبی وصل کنه به ماشینش، استفاده از ریداکس واسه جابهجا کردن دیتا بین کامپوننتها تو ریاکت هم دقیقا همین موضوع هستش، ریاکت داخل خودش یه کانتکست داره پس دیگه دلیلی نداره که ما بیایم ریداکس رو نصب کنیم ...
- شاید الان پیش خودتون بگید ریداکس خیلی خفنه چون کلی middle-ware داره که میشه باهاش دیتا فچ کرد (redux-thunk) و یا دیتا رو persist کرد (redux-persist) و یا استیت رو بین تبهای مروگر سینک کرد و ...
+ همه اینارو میشه با کانتکسهم پیاده سازی کرد، برای مثال persist شدن دیتا نهایتا ۵ خط کد نیاز داره :)، واسه دیتا فچ کردن نیازی به میدل ور ندارید و واسه سینک شدن اطلاعات بین تبهای مرورگر کافیه از broadcast api استفاده کنید.
- یا شاید پیش خودتون بگید مدیریت استیت بدون reducer خیلی سخت میشه !
+ باید بگم تیم سازنده ریاکت دقیقا همون کد reducer که داخل ریداکس هستش رو کپی کردن داخل هوک useReducer
- ریداکس action creator داره، اینو چی میگی آقای نویسنده
+ کانتکست هم میتونه action creator داشته باشه هم میتونه نداشته باشه بستگی داره به کاری که میخوای انجام بدی.
- ولی ما قوم بنی اسرائیلیم هنوزم از ریداکس استفاده میکنیم
+ =)
برای همین یکسری مثال و کلی نکته برای optimize کردن کانتکست دارم که داخل قسمت دوم مقاله بهشون اشاره میکنم.
ادامه مطالب رو سعی می کنم تا چند روز آینده در قالب مقاله دیگهایی تکمیل کنم و لینکش رو همینجا قرار بدم. میتونید وب سایتی که فقط و فقط با استفاده از کانتکست نوشتم رو از آدرس staging.antivirus.ir ببینید و چند تا صفحه باز کنید و توی یکی از صفحهها یک محصول به سبدخرید اضافه کنید و ببینید تو صفحات دیگه چه اتفاقی رخ میده.
تا زمان نوشته شدن قسمت دوم این چندتا لینک رو مطالعه کنید:
خوشحال میشم بدونم این مقاله مفید واقع شده یا نه! و آیا شما شروع به استفاده از کانتکست به جای ریداکس میکنید یا نه ؟
مطلبی دیگر از این انتشارات
استفاده از context api یا Redux (به دور از تعصب)
مطلبی دیگر از این انتشارات
ESLint و Prettier برای React
مطلبی دیگر از این انتشارات
حذف render اضافی کامپوننتهای ریاکت با batch