يقول مؤلف المادة ، التي ننشر ترجمتها اليوم ، أنه يجب عليه استخدام Vue في العمل وقد درس جيدًا هذا الإطار. ومع ذلك ، كان دائمًا فضوليًا لمعرفة كيف تسير الأمور في عوالم أخرى ، أي في عالم التفاعل.
لقد قرأ الوثائق وشاهد بعض مقاطع الفيديو التدريبية ، وعلى الرغم من أن كل هذا بدا مفيدًا للغاية بالنسبة له ، فقد أراد حقًا أن يفهم حقًا الفرق بين React و Vue. بالنسبة له ، لم يكن البحث عن الاختلافات بين الأطر هو معرفة ما إذا كانوا يدعمون نموذج الكائن الظاهري للمستند ، أو كيفية عرض الصفحات بالضبط. أراد شخصًا ما أن يشرح له ميزات الرمز ، ليوضح ما يجري فيه. كان يأمل في العثور على مقال مخصص لاكتشاف مثل هذه الاختلافات فقط ، بعد أن قرأ أن شخصًا يعرف Vue أو React فقط (أو شخصًا جديدًا تمامًا في تطوير الويب) يمكنه فهم الاختلافات بين هذه الأطر بشكل أفضل.

ومع ذلك ، لم يتمكن من العثور على مثل هذه المقالة. قادته هذه الحقيقة إلى فهم أنه كان عليه هو نفسه أن يأخذ مثل هذه المقالة والكتابة على طول الطريق ، وفهم أوجه التشابه والاختلاف بين React و Vue. في واقع الأمر ، هنا وصف لتجربته بالمقارنة بين هذين الإطارين.
أحكام عامة
Vue أو رد فعل؟بالنسبة للتجربة ، قررت إنشاء اثنين من تطبيقات المهام الواجبة القياسية إلى حد ما والتي تسمح للمستخدم بإضافة عناصر إلى قائمة المهام وإزالتها منها. تم تطوير كلا التطبيقين باستخدام
create-react-app
القياسية (
create-react-app
لـ React و
vue-cli
لـ Vue). CLI ، إذا لم يكن أحد يعرف ، هو اختصار يرمز إلى واجهة سطر الأوامر ، أي واجهة سطر الأوامر.
أقترح الآن إلقاء نظرة على مظهر التطبيقات المعنية هنا.
التطبيقات التي تم إنشاؤها بواسطة Vue و Reactإليك المستودعات التي تحتوي على الكود الخاص بهذه التطبيقات:
Vue ToDo ،
React ToDo .
يتم استخدام نفس رمز CSS هناك وهناك ، والفرق الوحيد هو مكان الملفات المقابلة بالضبط. في ضوء ذلك ، دعونا نلقي نظرة على هيكل المشاريع.
هيكل المشروع باستخدام Vue و Reactكما ترون ، هيكل هذين المشروعين متطابق تقريبًا. الاختلاف الرئيسي الوحيد هو أن تطبيق React يحتوي على ثلاثة ملفات CSS ، بينما لا يحتوي عليها تطبيق Vue على الإطلاق. والسبب في ذلك هو أنه عند استخدام
create-react-app
، تكون مكونات React مجهزة بملفات CSS المصاحبة ، وتتخذ Vue CLI نهجًا مختلفًا عندما يتم الإعلان عن الأنماط داخل ملف مكون محدد.
ونتيجة لذلك ، يتيح لنا كل من النهج والآخر تحقيق نفس الهدف ، في حين لا شيء يمنعنا ، إذا رغبت في ذلك ، من تنظيم الأنماط بشكل مختلف عن Vue أو React. في الواقع ، كل هذا يرجع إلى التفضيلات الشخصية للشخص الذي أنشأ مشروع الويب. على سبيل المثال ، تتم مناقشة موضوع هيكلة CSS باستمرار في مجتمعات المطورين. الآن نتبع فقط مناهج CSS القياسية المنصوص عليها في CLI للأطر المعنية.
ومع ذلك ، قبل أن نمضي قدمًا ، دعنا نلقي نظرة على شكل مكون Vue و React النموذجي.
إليك كود مكون Vue (في مشروعنا ، يوجد في ملف
ToDoItem.vue
).
<template> <div class="ToDoItem"> <p class="ToDoItem-Text">{{todo.text}}</p> <div class="ToDoItem-Delete" @click="deleteItem(todo)">- </div> </div> </template> <script> export default { name: "to-do-item", props: ['todo'], methods: { deleteItem(todo) { this.$emit('delete', todo) } } } </script> <style> .ToDoItem { display: flex; justify-content: center; align-items: center; } .ToDoItem-Text { width: 90%; background-color: white; border: 1px solid lightgrey; box-shadow: 1px 1px 1px lightgrey; padding: 12px; margin-right: 10px; } .ToDoItem-Delete { width: 20px; padding: 5px; height: 20px; cursor: pointer; background: #ff7373; border-radius: 10px; box-shadow: 1px 1px 1px #c70202; color: white; font-size: 18px; margin-right: 5px; } .ToDoItem-Delete:hover { box-shadow: none; margin-top: 1px; margin-left: 1px; } </style>
هنا هو رمز لمكون رد فعل (ملف
ToDoItem.js
).
import React, {Component} from 'react'; import './ToDoItem.css'; class ToDoItem extends Component { render() { return ( <div className="ToDoItem"> <p className="ToDoItem-Text">{this.props.item}</p> <div className="ToDoItem-Delete" onClick={this.props.deleteItem}>-</div> </div> ); } } export default ToDoItem;
حان الوقت الآن للتعمق في التفاصيل.
كيف يتم تعديل البيانات؟
ويطلق على تغيير البيانات أيضًا "تغيير البيانات". نحن نتحدث عن التغييرات التي تم إجراؤها على البيانات التي تخزنها تطبيقاتنا. لذا ، إذا كنا بحاجة إلى تغيير اسم شخص معين من "John" إلى "Mark" ، فإننا نتحدث عن "طفرة البيانات". يكمن الاختلاف الرئيسي بين React و Vue في نهج تغيير البيانات. أي أن Vue ينشئ كائن
data
فيه البيانات ، ويمكن تغيير محتوياته بحرية. تقوم React بإنشاء كائن حالة يتم فيه تخزين حالة التطبيق ، وعند العمل معه ، يلزم بذل جهد إضافي لتغيير البيانات. ومع ذلك ، في React ، يتم ترتيب كل شيء بهذه الطريقة لسبب ما ، سنتحدث عنه أدناه ، وبدايةً سننظر في الأشياء المذكورة أعلاه.
هذا هو شكل كائن
data
يستخدمه Vue.
data() { return { list: [ { todo: 'clean the house' }, { todo: 'buy milk' } ], } },
إليك ما يبدو عليه كائن
state
المستخدم في React:
constructor(props) , ], }; };
كما ترون ، في كلتا الحالتين وصفنا نفس البيانات ، فقد تم تصميمها بشكل مختلف. ونتيجة لذلك ، يمكننا القول أن نقل البيانات الأولية إلى المكونات في Vue و React يبدو متشابهًا جدًا. ولكن ، كما سبق ذكره ، تختلف طرق تغيير البيانات الموجودة في هذه الأطر.
لنفترض أن لدينا عنصر بيانات مثل
name: 'Sunil'
. ثم قمت بتعيين خاصية
name
اسمي الخاص.
في Vue ، يمكنك الوصول إلى هذه البيانات باستخدام
this.name
. وإليك كيفية تغييرها:
this.name = 'John'
. لا أعرف بالضبط كيف سأشعر إذا تغير اسمي حقًا ، ولكن في Vue يعمل مثل هذا.
في React ، يمكنك الوصول إلى نفس البيانات باستخدام
this.state.name
. لكن تغييرها عن طريق كتابة شيء مثل
this.state.name = 'John'
غير ممكن ، لأن React لديه قيود تمنع مثل هذه التغييرات في البيانات. لذلك ، في React ، يجب عليك استخدام شيء مثل
this.setState({name: 'John'})
.
نتيجة مثل هذه العملية هي نفسها التي تم الحصول عليها بعد إجراء عملية أبسط في Vue. يجب عليك كتابة المزيد من التعليمات البرمجية في React ، ولكن في Vue يوجد شيء مثل إصدار خاص من وظيفة
setState
، والذي يتم استدعاؤه عندما يبدو تغيير بسيط للبيانات. لذلك ، للتلخيص ، يتطلب
setState
استخدام
setState
مع وصف البيانات التي تحتاج إلى تغيير ، ويعمل Vue على افتراض أن المطور يرغب في استخدام شيء مشابه عن طريق تغيير البيانات داخل كائن
data
.
الآن دعونا نسأل أنفسنا لماذا تم
setState
ولماذا هناك حاجة إلى وظيفة
setState
على الإطلاق. يمكنك العثور على إجابات لهذه الأسئلة من
Revant Kumar : "هذا لأن React يسعى إلى إعادة تنفيذ بعض عمليات
shouldComponentUpdate
دورة الحياة ، عند تغيير الحالة ، مثل
componentWillReceiveProps
shouldComponentUpdate
،
shouldComponentUpdate
، و
shouldComponentUpdate
،
shouldComponentUpdate
، و
shouldComponentUpdate
. يتعلم أن الحالة تغيرت عند استدعاء وظيفة
setState
. إذا كنت ستقوم بتغيير الحالة مباشرة ، فسيتعين على React القيام بالمزيد من العمل لتتبع التغييرات ، وتحديد أي من حلقات دورة الحياة التي سيتم تشغيلها ، وما إلى ذلك. ونتيجة لذلك ، يستخدم
setState
لجعل الحياة
setState
. "
الآن بعد أن اكتشفنا تغييرات البيانات ، دعنا نتحدث عن كيفية إضافة عناصر جديدة إلى قائمة المهام في كلا الإصدارين من تطبيقنا.
أضف عناصر جديدة إلى قائمة المهام
رد الفعل
إليك كيفية القيام بذلك في React.
createNewToDoItem = () => { this.setState( ({ list, todo }) => ({ list: [ ...list, { todo } ], todo: '' }) ); };
يحتوي الحقل المستخدم
input
البيانات (
input
) على
value
السمة. يتم تحديث هذه السمة تلقائيًا من خلال استخدام زوج من الوظائف المترابطة التي تشكل ما يسمى ربط البيانات ثنائي الاتجاه (إذا لم تكن قد سمعت بهذا من قبل - انتظر قليلاً ، سنتحدث عن هذا في القسم الخاص بإضافة عناصر إلى تطبيق Vue). نقوم بإنشاء هذا النوع من الاتصال ثنائي الاتجاه بسبب وجود
onChange
إضافي
onChange
للأحداث مرفق بحقل
input
. دعنا نلقي نظرة على رمز هذا الحقل حتى تتمكن من فهم ما يحدث هنا.
<input type="text" value={this.state.todo} onChange={this.handleInput}/>
يتم
handleInput
وظيفة
handleInput
عندما تتغير قيمة حقل
input
. يؤدي هذا إلى تحديث عنصر
todo
، الموجود داخل كائن
state
، عن طريق تعيينه على القيمة الموجودة في حقل
input
. هذا ما تبدو عليه وظيفة
handleInput
.
handleInput = e => { this.setState({ todo: e.target.value }); };
الآن ، عندما ينقر المستخدم على الزر
+
في صفحة التطبيق لإضافة سجل جديد إلى القائمة ،
createNewToDoItem
الوظيفة
this.setState
طريقة
this.setState
وتمريرها الوظيفة. هذه الوظيفة تأخذ معلمتين. الأول هو صفيف
list
بالكامل من كائن
state
، والثاني هو عنصر المهام الذي يتم تحديثه بواسطة وظيفة
handleInput
. تقوم الدالة بعد ذلك بإرجاع كائن جديد يحتوي على صفيف
list
القديم ، ويضيف عنصر
todo
جديدًا إلى نهاية هذا الصفيف. يتم تنظيم العمل بالقائمة باستخدام عامل
spread
(إذا لم تكن قد استوفته من قبل ، فكن على دراية بأن هذه إحدى الميزات الجديدة لـ ES6 وابحث عن تفاصيل حولها).
أخيرًا ، يتم كتابة سلسلة فارغة في
todo
، والتي تقوم تلقائيًا بتحديث
value
في حقل
input
.
▍Vue
يتم استخدام البناء التالي لإضافة عنصر جديد إلى قائمة المهام في Vue.
createNewToDoItem() { this.list.push( { 'todo': this.todo } ); this.todo = ''; }
في Vue ، يحتوي حقل الإدخال على توجيه
v-model
. يسمح لك بتنظيم ربط البيانات في اتجاهين. ألق نظرة على رمز هذا الحقل وتحدث عما يحدث هنا.
<input type="text" v-model="todo"/>
يربط التوجيه على شكل
toDoItem
v-model
حقل بمفتاح موجود في كائن بيانات يسمى
toDoItem
. عند تحميل الصفحة ، يتم كتابة سطر فارغ في
toDoItem
، يبدو الأمر مثل
todo: ''
.
إذا كان هناك بالفعل بعض البيانات ، شيء مثل
todo: 'add some text here'
، فسيدخل النص نفسه في حقل الإدخال ، أي -
'add some text here'
. على أي حال ، إذا عدنا إلى المثال بسلسلة فارغة ، فسوف يقع النص الذي ندخله في الحقل ، بسبب ربط البيانات ، في خاصية
todo
. هذا ربط بيانات ثنائي الاتجاه ، أي أن إدخال بيانات جديدة في الحقل يؤدي إلى كتابة هذه البيانات إلى كائن
data
، ويؤدي تحديث البيانات في الكائن إلى ظهور هذه البيانات في الحقل.
تذكر الآن
createNewToDoItem()
التي تحدثنا عنها أعلاه. كما ترون ، نضع محتويات
todo
في صفيف
list
، ثم نكتب سلسلة فارغة للقيام بها.
إزالة عناصر من قائمة
رد الفعل
في رد الفعل ، يتم تنفيذ هذه العملية على هذا النحو.
deleteItem = indexToDelete => { this.setState(({ list }) => ({ list: list.filter((toDo, index) => index !== indexToDelete) })); };
أثناء
deleteItem
وظيفة
deleteItem
في ملف
ToDo.js
، يمكنك الوصول إليها دون مشاكل من
ToDoItem.js
، أولاً تمرير هذه الوظيفة كخاصية إلى
<ToDoItem/>
. إليك ما يبدو عليه:
<ToDoItem deleteItem={this.deleteItem.bind(this, key)}/>
هنا نقوم بتمرير الوظيفة ، مما يجعلها متاحة للمكونات الفرعية. بالإضافة إلى ذلك ، فإننا نربط
this
ونمر المعلمة
key
. يتم استخدام هذه المعلمة بواسطة الوظيفة لتمييز عنصر
ToDoItem
المراد حذفه من العناصر الأخرى. ثم ، داخل مكون
ToDoItem
، نقوم بما يلي.
<div className="ToDoItem-Delete" onClick={this.props.deleteItem}>-</div>
كل ما يلزم القيام به للوصول إلى الوظيفة الموجودة في المكون الأصلي هو استخدام
this.props.deleteItem
.
▍Vue
يتم حذف عنصر قائمة في Vue على هذا النحو.
onDeleteItem(todo){ this.list = this.list.filter(item => item !== todo); }
يتطلب Vue نهجًا مختلفًا قليلاً لإزالة العناصر عن تلك التي استخدمناها في React. وبالتحديد ، هناك ثلاث خطوات يجب اتخاذها.
أولاً ، إليك ما عليك القيام به في العنصر الذي تحتاج إلى استدعاء الوظيفة لحذفها.
<div class="ToDoItem-Delete" @click="deleteItem(todo)">-</div>
ثم تحتاج إلى إنشاء وظيفة
emit
كطريقة في المكون
ToDoItem.vue
(في هذه الحالة ، في
ToDoItem.vue
) ، والتي تبدو
ToDoItem.vue
.
deleteItem(todo) { this.$emit('delete', todo) }
علاوة على ذلك ، قد تلاحظ أننا نقوم بإضافة
ToDoItem.vue
داخل
ToDo.vue
.
<ToDoItem v-for="todo in list" :todo="todo" @delete="onDeleteItem" // <-- this :) :key="todo.id" />
هذا ما يسمى مستمع الأحداث المخصصة. يستجيب
emit
المكالمات مع خط
delete
. إذا
onDeleteItem
حدثًا مشابهًا ،
onDeleteItem
وظيفة
onDeleteItem
. وهو موجود داخل
ToDo.vue
، وليس في
ToDoItem.vue
. تقوم هذه الوظيفة ، كما ذكر أعلاه ، بتصفية مصفوفة المهام الموجودة في كائن
data
أجل إزالة العنصر الذي تم النقر عليه.
بالإضافة إلى ذلك ، تجدر الإشارة إلى أنه في المثال باستخدام Vue ، يمكن للمرء ببساطة كتابة الرمز المرتبط بوظيفة
@click
داخل
@click
. قد يبدو هذا.
<div class="ToDoItem-Delete" @click="$emit('delete', todo)">-</div>
سيؤدي هذا إلى تقليل عدد الخطوات المطلوبة لإزالة عنصر قائمة من ثلاث إلى اثنتين. كيفية المتابعة هي مسألة تفضيل المطور.
لتلخيص هذا القسم ، يمكننا القول أنه في React ، يتم تنظيم الوصول إلى الوظائف الموضحة في المكونات الرئيسية من خلال هذا.
props
(بالنظر إلى أن
props
تنتقل إلى المكونات الفرعية ، وهي تقنية قياسية يمكن العثور عليها حرفياً في كل مكان). في Vue ، يجب أن تقوم المكونات الفرعية بتشغيل الأحداث باستخدام وظيفة
emit
، وتتم معالجة هذه الأحداث بالفعل بواسطة المكون الأصلي.
العمل مع مستمعي الأحداث
رد الفعل
في React ، فإن مستمعي الأحداث لشيء بسيط ، مثل حدث النقر ، بسيط للغاية. فيما يلي مثال على إنشاء معالج حدث
click
لزر يقوم بإنشاء عنصر مهام جديد.
<div className="ToDo-Add" onClick={this.createNewToDoItem}>+</div>
يتم ترتيب كل شيء ببساطة هنا ، فهو يشبه إلى حد كبير معالجة مثل هذه الأحداث باستخدام JavaScript خالص.
تجدر الإشارة إلى أنه هنا ، يستغرق إعداد مستمعي الأحداث للضغط على ضغطات المفاتيح ، على سبيل المثال ، لـ
Enter
، وقتًا أطول قليلاً من Vue. هنا تحتاج إلى معالجة
onKeyPress
على النحو التالي. هنا هو رمز حقل الإدخال.
<input type="text" onKeyPress={this.handleKeyPress}/>
handleKeyPress
وظيفة
handleKeyPress
وظيفة
createNewToDoItem
عندما تتعرف على
createNewToDoItem
في
Enter
. يبدو هذا.
handleKeyPress = (e) => { if (e.key === 'Enter') { this.createNewToDoItem(); } };
▍Vue
من السهل جدًا تكوين معالجات الأحداث في Vue. يكفي استخدام الرمز
@
، ثم تحديد نوع المستمع الذي نريد استخدامه.
على سبيل المثال ، لإضافة مستمع أحداث النقر ، يمكنك استخدام الكود التالي.
<div class="ToDo-Add" @click="createNewToDoItem()">+</div>
يرجى ملاحظة أن
@click
هي اختصار لـ
v-on:click
. إن مستمعي حدث Vue جيدون في التحكم الدقيق جدًا. على سبيل المثال ، سيؤدي إرفاق بناء
.once
إلى المستمع إلى تشغيل المستمع مرة واحدة فقط.
هناك العديد من الاختصارات التي تبسط كتابة المستمعين الذين يستجيبون لضغطات المفاتيح على لوحة المفاتيح. في رد الفعل ، كما قلنا ، يستغرق هذا وقتًا أطول من Vue. هنا يتم ذلك ببساطة شديدة.
<input type="text" v-on:keyup.enter="createNewToDoItem"/>
تمرير البيانات إلى المكونات الفرعية
رد الفعل
في React ، يتم تمرير الخصائص إلى المكون الفرعي عند إنشائه. على سبيل المثال ، مثل هذا:
<ToDoItem key={key} item={todo} />
هنا يمكنك رؤية خاصيتين تم تمريرهما إلى مكون
ToDoItem
. من الآن فصاعدًا ، يمكن الوصول إليها في المكون
this.props
عبر
this.props
.
على سبيل المثال ، للوصول إلى خاصية
item.todo
، ما
this.props.item
سوى استخدام
this.props.item
.
▍Vue
في Vue ، يتم أيضًا تمرير الخصائص إلى المكونات الفرعية عند إنشائها.
<ToDoItem v-for="todo in list" :todo="todo" :key="todo.id" @delete="onDeleteItem" />
بعد ذلك ، يتم تمريرها إلى صفيف
props
للمكون الفرعي ، على سبيل المثال ، باستخدام
props: [ 'todo' ]
بناء. يمكنك الوصول إلى هذه الخصائص في المكونات الفرعية بالاسم ، في حالتنا هو اسم
'todo'
.
تمرير البيانات إلى المكون الأصلي
رد الفعل
في React ، يتم تمرير الوظيفة أولاً إلى المكون الفرعي كخاصية حيث يتم استدعاء المكون الفرعي. ثم يتم التخطيط لاستدعاء هذه الوظيفة ، على سبيل المثال ، عن طريق إضافتها
this.props.whateverTheFunctionIsCalled
onClick
، أو عن طريق الاتصال بها عن طريق استدعاء
this.props.whateverTheFunctionIsCalled
. يؤدي هذا إلى استدعاء الوظيفة الموجودة في المكون الأصل. يتم وصف هذه العملية في قسم إزالة العناصر من القائمة.
▍Vue
عند استخدام Vue ، في مكون فرعي ، يكفي كتابة دالة تقوم بتمرير البيانات إلى الوظيفة الأصلية. يتم كتابة دالة في المكون الأصلي الذي يستمع لأحداث نقل القيمة. عندما يحدث حدث مماثل ، تسمى هذه الوظيفة. كما هو الحال مع React ، يمكن العثور على وصف لهذه العملية في قسم إزالة العناصر من القائمة.
الملخص
تحدثنا عن كيفية إضافة البيانات وإزالتها وتعديلها في تطبيقات Vue و React ، وكيفية نقل البيانات ، في شكل خصائص ، من المكونات الأم إلى الأطفال ، وكيفية إرسال البيانات من المكونات الفرعية إلى الآباء. نعتقد أنه بعد تحليل أمثلة التشابه والاختلاف ، فإن Vue و React ظاهران ، كما يقولون ، بالعين المجردة.
هناك بالطبع العديد من الاختلافات الصغيرة الأخرى بين React و Vue ، لكنني آمل أن يكون ما تناولناه هنا بمثابة أساس جيد لفهم كيفية عمل هذه الأطر. غالبًا ما يتم تحليل الأطر عند اختيار النظام الأساسي المناسب لمشروع جديد. نأمل أن تساعد هذه المواد في اتخاذ مثل هذا الاختيار.
أعزائي القراء! ما هي الاختلافات بين React و Vue ، في رأيك ، الأكثر أهمية التي تؤثر على اختيار إطار معين ، على سبيل المثال ، كأساس لمشروع معين؟
