Redux چیست؟ + مزایا و عملکرد ریداکس
ابزارها و کتابخانه های بسیاری برای توسعه وب وجود دارند که استفاده از هرکدام بدون آگاهی از مزایا و ویژگی های آن کار عقلانی به نظر نمی رسد. کتابخانه ریداکس Redux یکی از این ابزارهای جدید است که طرفداران بسیاری نیز دارد. امروز در داناپ قصد داریم پس از بررسی Redux کاربردهای آن را نیز به شما معرفی کنیم پس با ما همراه باشید.
ریداکس چیست؟
ریداکس یک State Container قابل پیش بینی برای اپلیکیشن های جاوا اسکریپت است، برنامه نویس با استفاده از آن قادر است اپلیکیشنی را توسعه دهد که به صورت پایدار در محیط های مختلف اجرا شده و همچنین به راحتی قابل آزمایش باشد.
به زبان ساده تر Redux یک ابزار مدیریت State است. اگرچه اغلب همراه با فریم ورک React مورد استفاده توسعه دهندگان قرار می گیرد ولی امکان استفاده از آن در کنار دیگر فریم ورک ها و کتابخانه های جاوا اسکریپت نیز امکان پذیر است. ریداکس (با توجه به Dependencies) حدود 2 کیلوبایت حجم دارد، بنابراین سایز Asset های اپلیکیشن را افزایش نمی دهد.
در حقیقت با استفاده از ریداکس، State های اپلیکیشن در یک مخزن نگهداری می شوند و دسترسی هر کامپوننت به تمامی State ها نیز امکان پذیر است.
چرا شما به یک ابزار مدیریت State نیاز دارید؟
در ابتدای این مقاله به این نکته اشاره کردیم که Redux در واقع یک ابزار مدیریت State است. حال می خواهیم دلیل استفاده از این ابزار را نیز بررسی کنیم.
بیشتر کتابخانه ها نظیر React، Angular و غیره ویژگی هایی دارند که به کامپوننت ها این امکان را می دهد تا به صورت داخلی و بدون دخالت هرگونه ابزار بیرونی، حالت (State) خود را مدیریت کنند. این موضوع برای اپلیکیشن هایی که کامپوننت های کم تعدادی دارند صدق می کند اما هرچقدر که یک پروژه بزرگتر می شود مدیریت State اشتراکی بین کامپوننت های آن امری بسیار گیج کننده و دشوار خواهد شد.
دانستن این موضوع که یک State در چه مکانی باید قرار داشته باشد در اپلیکیشنی که دیتا در بین مولفه های آن تقسیم می شود امری پیچیده به شمار می رود. به عبارت دیگر در حالت ایده آل دیتا فقط باید در یک کامپوننت قرار داشته باشد اما تقسیم آن در بین کامپوننت های یکسان کار آسانی به نظر نمی رسد.
برای مثال اشتراک گذاری دیتا بین مولفه های مشابه در React بدین گونه است که State باید در یک کامپوننت مادر (Parent) قرار داده شود و سپس این کامپوننت مادر با استفاده از یک Method بروزرسانی State را انجام داده و آن را به عنوان props به کامپوننت های یکسان پاس می دهد.
در تصویر زیر یک مثال ساده از کامپوننت Login در React را مشاهده می کنید که در آن ورودی کامپوننت Login بر روی نمونه مشابه خود (Status Component) تاثیر می گذارد :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
class App extends React.Component { constructor(props) { super(props); // First the Parent creates a state for what will be passed this.state = { userStatus: "NOT LOGGED IN"} this.setStatus = this.setStatus.bind(this); } // A method is provided for the child component to update the state of the // userStatus setStatus(username, password) { const newUsers = users; newUsers.map(user => { if (user.username == username && user.password === password) { this.setState({ userStatus: "LOGGED IN" }) } }); } render() { return ( <div> // the state is passed to the sibling as a props as is updated whenever // the child component changes the input <Status status={this.state.userStatus} /> // this method is passed to the child component as a props which it // uses to change the state of the userStatus <Login handleSubmit={this.setStatus} /> </div> ); } }); |
به خاطر داشته باشید که کامپوننت مادر به این دیتا احتیاجی ندارد اما چون زیرشاخه های آن نیازمند تقسیم دیتا هستند، حتماً باید یک State تعریف شده باشد.
حال فرض کنید که اگر یک State بین کامپوننت های جدا ازهم تقسیم شود چه اتفاقی خواهد افتاد. در حقیقت یک State تا جایی که نیاز باشد از یک کامپوننت به دیگری پاس داده می شود. به طور کل یک State باید آنقدر به کامپوننت های مادر و کناریش متصل شود تا در نهایت به کامپوننت سرشاخه راه یابد. این موضوع باعث می شود که State غیرقابل پیش بینی شده و نگهداری شود و همچنین در برخی اوقات دیتا را به کامپوننت هایی که به آن نیاز ندارند پاس می دهد.
کاملاً مشخص است که با پیچیدگی اپلیکیشن مدیریت State ها نیز سخت تر می شود، برای همین شما باید از ابزار مدیریتی مانند Redux برای راحتی کار استفاده کنید.
Redux چطور کار می کند؟
نحوه کارکرد Redux بسیار ساده است به گونه ای که یک مخزن مرکزی تمام State های یک اپلیکیشن را در خود ذخیره می کند و هر کدام از کامپوننت ها بدون نیاز به ارسال props، می توانند به State های ذخیره شده دسترسی داشته باشند. ساختمان ریداکس از 3 بخش اصلی actions، store و reducers تشکیل شده است که هرکدام مزایایی برای Redux به ارمغان می آورند.
Actions
اکشن ها در حقیقت همان Event هستند که تنها راه ارسال دیتا از اپلیکیشن به مخزن Redux محسوب می شوند. این دیتا می تواند از تعامل با کاربر، فراخوانی API یا submission ها باشد. اکشن ها که در واقع Object های عادی جاوا اسکریپت هستند با استفاده از متد store.dispatch() ارسال می شوند، همچنین برای تعیین عملکرد باید به type property نیز مجهز شوند.اکشن ها از طریق action creator ساخته می شوند و باید اطلاعات مورد نیاز را از طریق پی لود (payload) در اختیار آنها قرار داد.
در ادامه مثالی از action در زمان login در یک اپلیکیشن را مشاهده خواهید کرد :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
{ type: "LOGIN", payload: { username: "foo", password: "bar" } } Here is an example of its action creator: const setLoginStatus = (name, password) => { return { type: "LOGIN", payload: { username: "foo", password: "bar" } } } |
همانطور که پیش تر اشاره کردیم برای ذخیره سازی، اکشن باید حاوی type property و Payload باشد.
Reducers
تقلیل دهنده ها یا همان reducers توابع خالصی هستند که State فعلی یک اپلیکیشن را دریافت کرده و پس از انجام عملیات، یک State جدید تحویل می دهد که در مخزن به عنوان Objects ذخیره خواهند شد. وظیفه آنها این است که در زمان ارسال action به مخزن، تغییرات state یک اپلیکیشن را تعیین نمایند.
در مثال زیر نحوه عملکرد Reducers در ریداکس را مشاهده خواهید کرد :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
const LoginComponent = (state = initialState, action) => { switch (action.type) { // This reducer handles any action with type "LOGIN" case "LOGIN": return state.map(user => { if (user.username !== action.username) { return user; } if (user.password == action.password) { return { ...user, login_status: "LOGGED IN" } } }); default: return state; } }; |
تقلیل دهنده ها (Reducers) به عنوان توابع خالص، تغییری در دیتای موجود در object ها یا عملکرد اپلیکیشن ایجاد نمی کنند به گونه ای که با دریافت object یکسان، همواره نتیجه مشابهی تولید می کنند.
Store
تنها یک مخزن در اپلیکیشن های ریداکس وجود دارد که state های آن را در خود نگهداری می کند. برنامه نویسان از طریق متدهای helper به state های ذخیره شده دسترسی پیدا کرده و پس از بروزرسانی آنها، می توانند اجازه ثبت یا لغو ثبت listener ها را صادر کنند. در مثال زیر ساخت store برای login اپلیکیشن را مشاهده خواهید کرد :
1 |
const store = createStore(LoginComponent); |
اکشن ها همیشه state های جدیدی را تحویل می دهند که به راحتی قابل پیش بینی هستند، در ادامه همان مثال کامپوننت login را بررسی خواهیم کرد تا با چگونگی تقویت کامپوننت توسط ریداکس نیز آشنا شویم:
1 2 3 4 5 6 7 8 9 10 |
class App extends React.Component { render() { return ( <div> <Status user={this.props.user.name}/> <Login login={this.props.setLoginStatus}/> </div> ) } } |
در Redux هیچ state کلی وجود ندارد و امکان دسترسی برای هرکدام از کامپوننت ها فراهم می باشد که این موضوع از رفت و آمد بی وقفه state در میان کامپوننت ها جلوگیری می کند. در زمان استفاده Redux به همراه React دیگر نیازی به لیفت state ها نیست، بنابراین پیگیری اکشن ها به راحتی امکان پذیر است.
همانطور که در مثال بالا مشاهده کردید، کامپوننت برای تقسیم دیتا بین زیر شاخه های خود نیازی به state یا method ندارد بنابراین نگهداری از اپلیکیشن به راحتی هرچه تمام تر صورت می پذیرد. اگرچه این موضوع مهم ترین مزیت Redux به شمار می رود اما در ادامه فواید دیگر این ابزار را بررسی خواهیم کرد.
مزایای Redux
1- State قابل پیش بینی :
وضعیت state در ریداکس همیشه قابل پیش بینی است، چرا که reducer ها توابعی خالص هستند، اگر اکشن و state مشابهی به یک reducer پاس داده شود همواره نتیجه ای یکسان حاصل می شود. علاوه بر این state غیرقابل تغییر و جهش است. بنابراین پیاده سازی task های دشوار مانند undo و redo نیز امکان پذیر است. سفر در زمان هم در ریداکس امکان پذیر است به گونه ای که می توان state های قبلی را مشاهده کرده و نتایج آنها را به صورت حقیقی بررسی کرد!
2- تعمیر و نگهداری :
ریداکس درمورد نظم و ترتیب کدها بسیار سخت گیر است، بنابراین اگر فردی با Redux آشنا باشد به راحتی ساختار اپلیکیشن های آن را نیز درک خواهد کرد و در نهایت تعمیر و نگهداری از آن برای توسعه دهندگان نیز راحت تر می شود.
3- رفع باگ :
دیباگ کردن یک اپلیکیشن از طریق Redux امری بسیار ساده به شمار می رود. در حقیقت به علت استفاده از state و action، شناسایی ارورهای مربوط به کد یا شبکه به راحتی امکان پذیر است.
4- قابلیت تستینگ :
به خاطر اینکه از function برای تغییر وضعیت state توابع خالص استفاده می شود، امکان تست اپلیکیشن های Redux به سادگی هرچه تمام تر امکان پذیر است.
5- ماندگاری state :
برنامه نویسان می توانند برخی از state های یک اپلیکیشن را در مخزن ریداکس نگهداری کرده تا در صورت نیاز آنها را بازیابی (restore) کنند.
6- رندرینگ سمت سرور (Server-side Rendering) :
برنامه نویسان با استفاده از Redux می توانند از طریق ارسال state اپلیکیشن به سرور و پاسخ به درخواست سرور، عملیات رندرنیگ اولیه اپلیکیشن را انجام دهند. سپس کامپوننت های مورد نیاز در HTML رندر شده و به کاربر تحویل داده می شود.
دیدگاهتان را بنویسید
برای نوشتن دیدگاه باید وارد بشوید.