ایجاد یک برنامه یکسان در Vue و React. تفاوت در چیست؟
به دلیل اینکه در محل کار از Vue استفاده میکردم، شناخت نسبتا خوبی از آن داشتم. با این حال، کنجکاو بودم بدانم «چمنزارهای آنسوی حصار چه شکلی است؟» (چمنزار در این مورد همان React است!)
مستندات و متون مربوط به React را خوانده و چندین ویدیو آموزشی هم تماشا کرده بودم. با وجود اینکه همه آنها عالی بودند اما چیزی که من میخواستم بدانم این بود که React و Vue چه تفاوتهایی دارند. منظورم از تفاوت، این نبود که آیا هر دو آنها دارای DOM های مجازی بودند یا خیر، یا اینکه پرداخت (Render) صفحات در هرکدام از آنها چگونه انجام میگیرد. چیزی که من میخواستم این بود که یک نفر وقت بگذارد و تفاوت کد را برای من توضیح دهد! به مقالهای نیاز داشتم که این موضوع را، برای کسی که تازه کار را با Vue یا React (یا به طورکلی توسعه وب) شروع کرده، به گونهای توضیح دهد که بتواند شناخت بهتری از تفاوتهای میان این دو به دست آورد.
متأسفانه، هیچ مقاله یا مطلبی که بتواند از عهده این کار برآمده و این موضوع را بهخوبی پوشش دهد، نیافتم. بنابراین به این نتیجه رسیدم که بایستی خودم دستبهکار شوم و شباهتها و تفاوتهای این دو را بیابم. به این ترتیب، با خودم فکر کردم که به همراه انجام این کار، کل روند انجام کار را نیز مستند کرده تا بالاخره مقالهای با این موضوع تولید شده و در دسترس دیگران قرار گیرد.
تصمیم گرفتم یک برنامه نسبتاً استاندارد «فهرست انجام کارها» بسازم که به کاربر امکان اضافه و حذف موارد از فهرست را میدهد. هر دو برنامه (یکی نوشتهشده با React و دیگری با Vue) با استفاده از CLI های پیشفرض (creat-react-app
در React و vue-cli
در Vue) ساخته شدهاند. ضمناً، CLI مخفف عبارت Command Line Interface (واسط خط فرمان یا واسط نوشتاری) است.
به هر جهت، این مقدمه تا همینجا هم طولانیتر از آن شده که پیشبینی میکردم. پس بیایید با بررسی سریع ظاهر دو برنامه کار را شروع کنیم:
کد CSS برای هر دو برنامه کاملاً یکسان است، اما مکان قرارگیری این کدها، متفاوت است. با درنظرگرفتن این موضوع، بیایید نگاهی به ساختار فایل دو برنامه بیاندازیم:
مشاهده خواهید کرد که ساختار هر دو نیز تقریباً
یکسان است. تنها تفاوت این است که برنامهای که با React ساخته شده دارای سه فایل CSS است درحالیکه برنامه ساختهشده با Vue هیچ فایل CSS ای ندارد.
دلیل آن، این است که در create-react-app، جزئی (Component) از React یک فایل همراه برای حفظ سبکهای آن خواهد داشت درحالیکه CLI کتابخانه Vue، شیوهای جامع و همهجانبه را در پیش گرفته و تمام سبکها درون فایل Component موجود (فعلی) اعلان میگردند.
هر دو برنامه درنهایت خروجی یکسانی دارند و نمیتوان گفت که امکان ساخت CSS ى متفاوت با React یا Vue وجود ندارد. درواقع این به ترجیح شخصی برمیگردد؛ بحث و گفتگوهای بسیاری در میان جامعه توسعهدهندگان درباره اینکه CSS چگونه باید باشد، وجود دارد؛ اما فعلاً، ما ساختار ارائه شده توسط این دو CLI را دنبال میکنیم.
پیش از اینکه جلوتر برویم، بیایید نگاهی کوتاه به یک نمونه جزء (Component) در Vue و React بیاندازیم:
اکنون، بیایید جزئیات اساسی و اصلی را بررسی
کنیم!
چگونه دادهها را جهش (تغییر)
میدهیم؟
نخست، منظور از «جهش داده (Mutate)» چیست؟ به نظر اصطلاحی فنی و تخصصی است، اینطور نیست؟ این اصطلاح در اصل، تنها به معنی تغییر دادههایی است که قبلا ذخیره کردهایم. بنابراین، اگر بخواهیم مقدار نام یک فرد را از John به Mark تغییر دهیم، درواقع «جهش داده» انجام دادهایم. تفاوت اصلی میان React و Vue در همین مورد است. درحالیکه Vue ذاتاً یک شیء داده ( Data Object) ایجاد میکند تا داده بتواند آزادانه بهروزرسانی شود، React یک شیء حالت (State Object) ایجاد میکند که برای بهروزرسانی شدن، به انجام عملیات بیشتری نیاز دارد.
React این عملیات اضافی را به دلیلی قانع کننده و سودمند درنظر گرفته که بعدا به شرح آن میپردازیم؛ اما بیایید ابتدا نگاهی به شیء داده در Vue و شیء حالت در React بیاندازیم:
همانگونه که مشاهده میکنید ما دادههایی یکسان به هر دو وارد کردهایم، اما هرکدام از آنها، این داده را به گونهای متفاوت برچسب زده است . بنابراین واردکردن دادههای اولیه به اجزاء (در هر دو کتابخانه) بسیار شبیه است. اما همانگونه که قبلاً گفتیم، تغییر (جهش) این دادهها در هرکدام از این دو متفاوت است.
فرض کنید یک عنصر دادهای بهصورت زیر داریم:
name: "Ehsan"
در Vue، به این داده با فراخوانی this.name
ارجاع میدهیم. همچنین میتوانیم با فراخوانی "this.name = "John
این عنصر را به روزرسانی کنیم. این کار باعث میشود که نام من به John تغییر کند.
در React، ما به همین بخش از داده با فراخوانی this.state.name
ارجاع میدهیم. در اینجا، تفاوت اصلی این است که ما نمیتوانیم به سادگی فقط بنویسیم "this.state.name = "John
، زیرا React به منظور جلوگیری از رخ دادن چنین جهشهایی (تغییرات) که به سادگی اتفاق میافتد و ناشی از بی دقتی و عدم توجه کافی است، محدودیتهایی در نظر گرفته است. ازاینرو، در React، این کار را در حالت کلی با نوشتن this.setState({name: "John"})
انجام میدهیم.
با وجود اینکه خروجی این کار در اصل همان است که در Vue به دست آورده بودیم، اما علت نوشتن آن بخش از کد اضافه این است که زمانی که یک بخش از داده بهروزرسانی میگردد، Vue ذاتاً به صورت پیشفرض، نسخه خودش از setState
را ترکیب میکند. پس به طور خلاصه، React به setState
و پس از آن داده به روزرسانی شده درون آن نیاز داشته و آن را درخواست میکند، درحالیکه Vue فرض میکند اگر شما مقدار درون شیء را به روزرسانی کردهاید، این کار (setState
) را نیز میخواهید انجام دهید. بنابراین، اصلاً چرا React این کار را انجام میدهد و به چه علتی setState موردنیاز است؟ اجازه دهید ببینیم Revanth Kumar دراین باره چه توضیحی میدهد:
«دلیل این امر این است زمانیکه حالت (state) تغییر میکند، React میخواهد هوکهای (Hooks) چرخههایی مانند:
componentWillReceiveProps
،shouldComponentUpdate
،componentWillUpdate
، پرداخت (render) وcomponentDidUpdate
را دوباره اجرا کند. React اطلاع دارد زمانی که شما تابعsetState
را فراخوانی کردهاید، حالت تغییر کرده است. اگر شما مستقیماً حالت را جهش (تغییر) دادهاید، React برای پیگیری و دنبال کردن تغییرات ایجاد شده و اینکه چه هوکهایی در چرخه را باید اجرا کند و امثال آن، بایستی کارهای بسیاری انجام دهد. بنابراین React به منظور ساده نمودن این کار ازuseState
استفاده مینماید.»
حال که جهشها را بررسی کرده و از سر راه برداشتیم، بیایید از طریق بررسی شیوه افزودن موارد جدید به دو برنامه «فهرست انجام کارها» (که یکی با React و دیگری با Vue نوشته شده)، به سراغ بررسی مطالب پایهای و اصولی برویم.
چگونه در فهرست انجام کارها، موردی جدید ایجاد کنیم؟
React:
createNewToDoItem = () => { this.setState( ({ list, todo }) => ({ list: [ ...list, { todo } ], todo: '' }) ); };
React چگونه موردی جدید به فهرست انجام کارها اضافه میکند؟
در React، فیلد ورودی ما دارای یک خصیصه است که مقدار (Value) نامیده میشود. این مقدار بهطور خودکار از طریق استفاده از تعدادی تابع به روز میشود که این توابع به منظور ایجاد چیزی شبیه شیوه انجام اتصال دوطرفه توسط Vue، باهم ادغام میشوند. ما این مورد (مشابه شیوه اتصال دوطرفه در Vue) را با اضافه نمودن یک onChange event listener اضافی به فیلد ورودی، ایجاد میکنیم. بیایید به فیلد ورودی نگاهی سریع بیندازیم تا موضوع را متوجه شوید:
تابع handInput هرزمان که مقدار فیلد ورودی تغییر کند، اجرا میگردد. این تابع، todo را که درون شیء حالت (State Object) جای گرفته، با تنظیم آن به هر چیزی که در فیلد ورودی قرار دارد، به روز میکند. این تابع، بهصورت زیر عمل میکند:
handleInput = e => { this.setState({ todo: e.target.value }); };
حال هر زمان که کاربر برای اضافه نمودن یک مورد جدید دکمه + را در صفحه فشار دهد، تابع createNewToDoItem
ذاتاً this.setState
را اجرا کرده و (خروجی) آن را به یک تابع منتقل میکند. این تابع به دو پارامتر نیاز دارد، پارامتر اول کل آرایه فهرست شیء حالت است و دومین پارامتر todo است (که توسط تابع handleInput به روز میشود). درنهایت، خروجی این تابع شیء جدیدی است که شامل کل فهرست قبلی و todo اضافه شده به انتهای آن است. پسازآن، کل فهرست با استفاده از اپراتور Spread اضافه میگردد (اگر تاکنون راجع با این عملگر چیزی نشنیدهاید، آن را در گوگل جستجو کنید. این عملگر یکی از سینتاکسهای ES6 است).
در آخر، todo را در یک استرینگ (String) خالی قرار میدهیم که به طور خودکار مقدار موجود در فیلد ورودی را به روز میکند.
Vue:
createNewToDoItem() { this.list.push( { 'todo': this.todo } ); this.todo = ''; }
Vue چگونه موردی جدید به فهرست انجام کارها اضافه میکند؟
در Vue، فیلد ورودی دارای قابلیتی است که v-model نام دارد. این قابلیت به ما امکان انجام کاری را میدهد که بهعنوان اتصال دوطرفه شناخته میشود. بیایید به فیلد ورودی نگاهی سریع بیندازیم، پسازآن موضوع را توضیح خواهیم داد:
V-model، ورودی این فیلد را به کلید موجود در شیء داده که toDoItem نام دارد، وصل میکند. وقتی صفحه بارگیری میشود، باید toDoItem را به صورت یک استرینگ خالی تنظیم کنیم، به این شکل: todo: ""
. اگر دادهای از قبل در آن وجود داشته باشد، مانند "todo: "add some text here
، فیلد ورودی با متن add some text here
که در داخل آن نمایش داده میشود، بارگذاری میگردد. در هرحال، همانگونه که قبلاً گفتیم، آن (toDoItem) را بهعنوان یک رشته خالی در نظر گرفته و هر متنی که در فیلد ورودی بنویسیم به مقدار todo متصل میگردد (متن نوشتهشده در فیلد ورودی در todo قرار میگیرد). این، یک اتصال دوطرفه کارآمد و مؤثر است (فیلد ورودی میتواند شیء داده را به روز کند و شیء داده میتواند فیلد ورودی را به روز کند).
بنابراین با نگاهی به کدcreateNewToDoItem()
که پیشتر ارائه شد، مشاهده میکنیم که کار انجامگرفته به این صورت است: ابتدا محتویات todo را به آرایه وارد و سپس todo را به یک رشته خالی به روزرسانی میکنیم.
چگونه
موردی را از فهرست انجام کارها حذف کنیم؟
React:
deleteItem = indexToDelete => { this.setState(({ list }) => ({ list: list.filter((toDo, index) => index !== indexToDelete) })); };
React چگونه موردی را از فهرست انجام کارها حذف میکند؟
بنابراین، باوجود اینکه تابع deleteItem در داخل ToDo.js قرار دارد، در مرحله اول، با استفاده از انتقال تابع deleteItem()
به عنوان یک ویژگی مربوط به ، به صورتی که در زیر بیان شده است، به سادگی توانستم در داخل ToDoItem.js به آن (تابع deleteItem) ارجاع دهم:
این انتقال به این دلیل انجام میگیرد که تابع (deleteItem) را در دسترس (جزء) فرزند قرار دهد. با وجود اینکه کلید، در هنگام انجام کلیک مورد استفاده قرار گرفته تا تابع یاد شده بتواند تشخیص دهد که کدام یک از ToDoItem ها باید حذف گردند، مشاهده خواهید نمود که ما علاوه بر انتقال این پارامتر (کلید)، this
را نیز متصل کرده و انتقال میدهیم. سپس، در داخل جزء ToDoItem ، موارد زیر را انجام میدهیم:
تنها کاری که نیاز است برای ارجاع به تابعی که در داخل جزء والد قرار دارد انجام دهیم، ارجاع به this.props.deleteItem
است.
Vue:
onDeleteItem(todo){ this.list = this.list.filter(item => item !== todo); }
Vue چگونه موردی را از فهرست انجام کارها حذف میکند؟
Vue این کار را با روشی انجام میدهد که کمی متفاوت است. در اینجا، بایستی سه مرحله را طی کنیم:
در مرحله نخست، روی عنصری که میخواهیم تابع را (برای آن) فراخوانی کنیم:
سپس باید یک تابع emit را بهعنوان method در داخل جزء فرزند (در این مورد ToDoItem.vue
) ایجاد کنیم که به شکل زیر است:
deleteItem(todo) { this.$emit('delete', todo) }
زمانیکه ToDoItem.vue
را درون ToDo.vue
اضافه میکنیم، درواقع به یک تابع ارجاع میدهیم:
<ToDoItem v-for="todo in list" :todo="todo" @delete="onDeleteItem" //
این همان چیزی است که به عنوان یک شنونده-رویداد (Event-listener) سفارشی شناخته میشود. این شنونده-رویداد، هر رویدادی را که در آن یک انتشار (emit) از طریق رشته “delete” راهاندازی و آغاز میشود، شنود میکند. اگر آن delete را بشنود، تابعی به نام onDeleteItem
را راهاندازی میکند. این تابع بهجای ToDoItem.vue
، در داخل ToDo.vue
قرار میگیرد. این تابع، همانطور که در آغاز گفته شد، صرفاً آرایه (array) todo را درون شیء داده فیلتر میکند تا موردی را که روی آن کلیک شده است، حذف کند.
همچنین شایان ذکر است که در مورد مثال Vue میتوانستم به صورت زیر، به سادگی بخش $emit
را در داخل شنونده @click
نیز بنویسم:
این کار میتواند تعداد مراحل را از ۳ به ۲ کاهش
دهد و انجام آن صرفاً یک ترجیح شخصی است.
به طور خلاصه، جزءهای (Components) فرزند در React از طریق this.props
به توابع والد دسترسی خواهند داشت (بهشرط اینکه شما این ویژگیها را (به جزء فرزند) انتقال دهید، که این عملی کاملاً استاندارد بوده و در سایر نمونههای React بارها با آن روبه رو خواهید شد)، درحالیکه در Vue، شما باید رویدادهای (جزء) فرزند را منتشر (emit) کنید که معمولاً (این رویدادها) در جزء والد گردآوری خواهند شد.
چگونه شنوندههای رویداد را ایجاد کنیم؟
React:
شنوندههای رویداد (Event listeners) برای موارد ساده مانند رویدادهای کلیک، ساده و سرراست هستند. در اینجا مثالی از چگونگی ایجاد یک رویداد کلیک برای دکمهای که یک مورد جدید ToDo (کار جدید) ایجاد میکند، ارائه شده است:
.
همان گونه که گفته شد، انجام این کار بسیار آسان بوده و تقریباً مشابه حالتی است که یک (رویداد) onClick درون خطی را با vanilla JS مدیریت و کنترل میکنیم. همانطور که در بخش Vue گفته شد، راهاندازی یک شنونده رویداد به منظور کنترل زمان فشرده شدن دکمه enter، به کار و زمان بیشتری نیاز دارد. انجام این کار، اصولاً نیاز به یک رویداد onKeyPress دارد که با فیلد ورودی، به صورت زیر، کنترل و مدیریت شود:
.
این تابع، هرزمان که تشخیص دهد کلید “enter” فشرده شده است، بهطور ذاتی، تابع createNewToDoItem
را به صورت زیر، راهاندازی میکند:
handleKeyPress = (e) => { if (e.key === ‘Enter’) { this.createNewToDoItem(); } };
Vue:
این کار (ایجاد شنوندههای رویداد) در Vue بسیار ساده است. تنها کافیست از نماد @ استفاده و پسازآن نوع شنونده رویدادی که میخواهیم پیادهسازی کنیم، استفاده کنیم. بهعنوان مثال، به منظور اضافه کردن یک شنونده رویداد کلیک، میتوانیم کد زیر را بنویسیم:
نکته: @click
درواقع شکل مختصر v-on:click
است. نکته جالب در مورد شنوندههای رویداد در Vue این است که میتوانید چیزهایی به آنها متصل کنید، مانند: .once
که از اینکه شنونده رویداد بیشتر از یکبار راهاندازی شود، جلوگیری میکند. همچنین تعدادی میانبر برای نوشتن (کد) شنونده-رویدادی که برای کنترل و مدیریت ضربه به کلیدها استفاده میشوند، نیز وجود دارد. علاوه برآن، به این نکته نیز پی بردم که ایجاد یک شنونده رویداد در React برای زمانی که دکمه enter، جهت اضافه نمودن موارد جدید ToDo ، فشرده میشود، کمی کار و زمان بیشتری نیاز دارد. در Vue، برای این کار به سادگی، صرفاً میتوان کد زیر را نوشت:
چگونه دادهها را به یک جزء فرزند انتقال دهیم:
React:
درواقع، ما ویژگیها (props) را در لحظهای که جزء (component) فرزند ساخته میشود به صورت زیر به آن (جزء فرزند) انتقال میدهیم:
در اینجا مشاهده میکنیم که دو ویژگی به جزء ToDoItem منتقل شده است. از این لحظه به بعد، میتوانیم در جزء فرزند از طریق this.props
به آنها ارجاع دهیم. بنابراین برای دسترسی به ویژگی item.todo
، تنها لازم است که this.props.item
را فراخوانی کنیم.
Vue:
در Vue نیز، ما ویژگیها را در لحظهای که جزء فرزند ساخته میشود بهصورت زیر به آن انتقال میدهیم:
پسازآنکه این کار انجام شد، ما آنها (ویژگیها) را از طریق props: [ "todo" ]
به آرایه ویژگیها در جزء فرزند انتقال میدهیم. این ویژگیها از این به بعد میتوانند با استفاده از نامشان در جزء فرزند ارجاع داده شوند، در این مورد، این کار با “todo” انجام میشود.
و حالا ما مقالهای که تفاوت React و Vue را بررسی کند، در اختیار داریم!
در این مقاله، ما به شیوه اضافه کردن، حذف و تغییر دادهها، انتقال داده در قالب ویژگی (prop) از والد به فرزند و ارسال داده از فرزند به والد در قالب شنوندههای رویداد، پرداختیم. البته تفاوتهای ظریف بسیار دیگری بین React و Vue وجود دارد، اما امیدوارم که مطالب این مقاله جهت استفاده بهعنوان پایه و اصول شناخت عملکرد هر دو چارچوب، به شما کمک کند.
این مقاله توسط Sunil Sandhu نوشته و در مدیوم منتشر شده است.
دیدگاهتان را بنویسید