React ו-Vue הם שניהם כלי JavaScript לבניית ממשקי משתמש מקומפוננטות (React קוראת לעצמה ספרייה, Vue קורא לעצמו progressive framework), והם חולקים את רוב הרעיונות: props מטה, אירועים מעלה, state ריאקטיבי, virtual DOM. ההבדלים המעשיים הם ש-React כותבת markup ב-JSX ומצפה ש-state יוחלף עם setter, ואילו Vue כותב markup ב-templates של HTML בתוך single-file components ומאפשר לשנות ערכים ריאקטיביים ישירות. הנה מונה ב-React:
ואותו מונה כ-single-file component של Vue (Counter.vue):
<script setup>
import { ref } from 'vue';
const count = ref(0);
</script>
<template>
<button @click="count++">Clicked {{ count }} times</button>
</template>
useState(0) הופך ל-ref(0), onClick הופך ל-@click, ו-{count} הופך ל-{{ count }}. ההבדל הגלוי הוא count++: Vue מאפשר לשנות את הערך במקום, ומערכת הריאקטיביות שלו שמה לב. React צריכה את setCount כי היא מרנדרת מחדש רק כשנותנים לה ערך חדש.
JSX מול single-file components
קומפוננטת React היא פונקציית JavaScript שמחזירה JSX. תנאים הם && או טרנרי, רשימות הן .map(), וסגנונות מגיעים מכל מה שבוחרים (קובצי CSS, CSS modules, framework של utilities).
קומפוננטת Vue היא בדרך כלל קובץ .vue עם שלושה בלוקים: <script setup> ללוגיקה, <template> ל-markup, ו-<style scoped> אופציונלי שה-CSS שלו חל רק על הקומפוננטה הזו. templates משתמשים ב-directives: v-if, v-for, v-model ל-binding דו כיווני של קלט, :prop כדי לקשור ערך ו-@event כדי להאזין. templates שומרים על markup קריא לכל מי שמכיר HTML; JSX נותן לכם את כל JavaScript בתוך ה-markup. Vue יכול להשתמש גם ב-JSX ו-React לא יכולה להשתמש ב-templates, אבל רוב הקוד בכל אחד מהם עוקב אחרי ברירת המחדל שלו.
הנה רשימה מסוננת, הפיצ'ר השני להשוואה.
נסו להקליד xyz כדי לראות את הודעת הרשימה הריקה, ואז מחקו את זה. גרסת ה-Vue:
<script setup>
import { ref, computed } from 'vue';
const fruits = ['Apple', 'Banana', 'Cherry', 'Grape', 'Mango', 'Peach'];
const query = ref('');
const visible = computed(() =>
fruits.filter((f) => f.toLowerCase().includes(query.value.toLowerCase()))
);
</script>
<template>
<input v-model="query" placeholder="Filter fruit" />
<ul>
<li v-for="fruit in visible" :key="fruit">{{ fruit }}</li>
<li v-if="visible.length === 0">No match</li>
</ul>
</template>
v-model מחליף את הזוג value ועוד onChange, ו-computed מחליף את המשתנה הרגיל. ב-React, visible מחושב מחדש בכל רינדור כי פונקציית הקומפוננטה רצה שוב; ב-Vue, computed שומר אותו ב-cache ומחשב אותו מחדש רק כש-query משתנה. שניהם משתמשים ב-key כדי להבחין בין פריטי רשימה.
מודל הריאקטיביות
זה ההבדל העמוק ביותר בין השניים.
React: state immutable ורינדורים מחדש. state הוא תמונת מצב. קוראים ל-setter עם ערך חדש, React מריצה שוב את פונקציית הקומפוננטה, משווה את ה-JSX החדש לישן, ומעדכנת את ה-DOM. React משווה ערכים עם Object.is, ולכן שינוי של אובייקט או מערך במקום והעברת אותו אחד בחזרה נראים כמו שום שינוי.
לחצו על "push() in place" ושום דבר לא משתנה על המסך, כי המערך הוא אותו אובייקט. אחר כך לחצו על "New array": הרינדור מציג גם את pushed, כי ה-mutation הקודם באמת קרה, ל-React פשוט לא הייתה סיבה להסתכל. הדף על useState מכסה את הדפוס הזה לעומק.
Vue: ערכים ריאקטיביים שאפשר לשנות. ref או אובייקט reactive רושמים מי קורא אותם (ref דרך ה-getter של .value שלו, אובייקט reactive דרך proxy). כשכותבים אליו, Vue יודע בדיוק אילו ערכים מחושבים, watchers וחלקי template תלויים בו ומעדכן רק אותם. ב-Vue, items.value.push('pushed') מעדכן את המסך. כותבים פחות טקס, ומוותרים על ההבטחה שערך אף פעם לא משתנה מתחת לרגליים.
אף אחד מהמודלים לא מהיר יותר בצורה שמשנה באפליקציות טיפוסיות. React עשויה להריץ יותר קוד קומפוננטות בכל שינוי ומסתמכת על memoization (ידני, או דרך React Compiler) כדי לדלג על עבודה; Vue עוקב אחרי תלויות בזמן ריצה ולכן מדלג על העבודה הזו כברירת מחדל.
Composition API מול הוקים
ה-Composition API של Vue 3 וההוקים של React פותרים את אותה בעיה: לשים state ולוגיקה קשורים יחד ולהשתמש בהם שוב בין קומפוננטות. Vue קורא לפונקציות לשימוש חוזר composables (useMouse()), ו-React קוראת להן הוקים מותאמים (useMouse()). הכללים שונים בגלל מתי הקוד רץ.
- מתי הוא רץ.
setupשל Vue רץ פעם אחת כשהקומפוננטה נוצרת. פונקציית קומפוננטה של React רצה בכל רינדור, וההוקים שבתוכה רצים איתה. - כללי סדר. React מתאימה הוקים לפי סדר הקריאות, ולכן אי אפשר לקרוא להם בתוך תנאים או לולאות. ל-Vue אין כלל כזה ל-
refול-computed, כי ה-setup רץ פעם אחת. - תלויות. אפקטים ו-memos של React מפרטים את התלויות שלהם במערך שאתם מתחזקים.
watchEffectו-computedשל Vue עוקבים אוטומטית אחרי מה שהם קוראים. - ערכים מיושנים. callback של React יכול ללכוד ערך state ישן מרינדור קודם (הבאג הקלאסי של
setInterval). callback של Vue קורא אתcount.valueבזמן הקריאה ותמיד רואה את הערך הנוכחי.
המודל של React הופך כל רינדור לפונקציה טהורה של props ו-state, שקל לבדוק ולחשוב עליה. המודל של Vue מבטל קבוצה של באגים סביב מערכי תלויות. מפתחים שמכירים אחד בדרך כלל קולטים את השני מהר.
אקוסיסטם
| React | Vue | |
|---|---|---|
| markup | JSX | templates של HTML בקובצי .vue (JSX אופציונלי) |
| עדכוני state | מחליפים עם setter, ואז רינדור מחדש | משנים ערך ריאקטיבי, התלויים מתעדכנים |
| שימוש חוזר בלוגיקה | הוקים מותאמים | composables |
| ערכים נגזרים | מחושבים בזמן הרינדור, useMemo | computed (שמור ב-cache) |
| binding דו כיווני לקלט | value ועוד onChange | v-model |
| CSS מבודד | לא מובנה (CSS modules, ספריות) | <style scoped> מובנה |
| ניתוב | React Router, TanStack Router, frameworks | Vue Router (רשמי) |
| state גלובלי | קונטקסט, Zustand, Redux Toolkit | Pinia (רשמי) |
| framework ל-full-stack | Next.js, React Router במצב framework | Nuxt |
| אפליקציות מובייל | React Native | אין אפשרות רשמית (Capacitor, NativeScript-Vue) |
| כלי build | Vite או framework | Vite |
| מתוחזק על ידי | Meta והקהילה | צוות ליבה עצמאי והקהילה |
הדפוס בטבלה הזו: צוות הליבה של Vue מתחזק את הראוטר, את ה-store ואת ה-devtools יחד, כך שלפרויקט Vue יש ברירת מחדל ברורה לכל אחד מהם. React משאירה אותם לקהילה, מה שנותן לכם יותר אפשרויות ויותר החלטות. Vite, כלי ה-build הרגיל לפרויקטים חדשים בשניהם, התחיל אצל היוצר של Vue.
עקומת למידה
Vue הוא לעיתים קרובות התחלה עדינה יותר. templates נקראים כמו ה-HTML שכבר מכירים, v-model מוריד את קוד ה-boilerplate של שדות מבוקרים, וערך ריאקטיבי מעדכן את המסך כשמשנים אותו. React מבקשת JSX ואת הרגל העדכון ה-immutable כבר בהתחלה, והדף על JSX הוא הדבר הראשון שרוב האנשים צריכים.
אחרי הבסיס, הפער מצטמצם. Vue מוסיף מושגים משלו (refs מול אובייקטים reactive, .value בסקריפטים אבל לא ב-templates, watchers), ו-React מוסיפה אפקטים, memoization ואת כללי ההוקים. מודעות דרושים באזור שלכם הן שובר שוויון שימושי יותר מתחביר.
מתי לבחור במה
בחרו ב-React כש:
- רוצים בחירה רחבה של ספריות וקומפוננטות מהקהילה, או מתכננים לבנות אפליקציות מובייל נייטיב עם React Native.
- אוהבים להחזיק לוגיקה ו-markup בפונקציית JavaScript אחת ורוצים framework כמו Next.js.
- הצוות שלכם מעריך עדכונים מפורשים ו-immutable שהופכים כל רינדור לקל למעקב.
בחרו ב-Vue כש:
- רוצים כלים רשמיים ותואמים לניתוב ול-state ופחות החלטות לקבל.
- בצוות שלכם יש מעצבים או מפתחי back-end שמרגישים בנוח עם templates של HTML.
- מוסיפים אינטראקטיביות לדפים קיימים שמרונדרים בשרת: אפשר להכניס את Vue לדף מתגית script ולגדול משם.
שניהם בשלים ומשמשים בפרודקשן חברות מכל גודל, והמושגים שלומדים באחד (קומפוננטות, props, state נגזר, רשימות עם keys) עוברים ישר לשני.
שאלות נפוצות
האם Vue קל יותר מ-React?
הרבה מתחילים מוצאים את Vue קל יותר בהתחלה, כי templates נראים כמו HTML רגיל ושינוי ערך ריאקטיבי (count.value++) מעדכן את המסך בלי setter. React מבקשת מכם ללמוד JSX ואת הכלל ש-state צריך להיות מוחלף, לא משונה. אחרי השבועות הראשונים הקושי דומה.
מה עדיף, React או Vue?
אף אחד מהם לא מנצח באופן כללי. React משאירה ניתוב ו-state לספריות של הקהילה ויש לה React Native למובייל. ל-Vue יש ראוטר, store ו-devtools רשמיים שמתוחזקים יחד, ו-templates שהרבה אנשים מוצאים קלים יותר לקריאה. בחרו את זה שהצוות שלכם או שוק העבודה משתמשים בו.
מה ההבדל בין ה-Composition API של Vue להוקים של React?
שניהם מקבצים לוגיקה עם state לפונקציות לשימוש חוזר. setup של Vue רץ פעם אחת לכל קומפוננטה ועוקב אחרי תלויות אוטומטית, כך שאין מערכי תלויות ואין closures מיושנים. פונקציית קומפוננטה של React רצה בכל רינדור, ולכן צריך לקרוא להוקים באותו סדר בכל פעם, ואפקטים מפרטים את התלויות שלהם.
האם Vue משתמש ב-JSX?
Vue תומך ב-JSX דרך פלאגין, אבל רוב קוד ה-Vue משתמש ב-templates של HTML בתוך single-file components (קובצי .vue). React משתמשת ב-JSX כמעט בכל מקום.
מה המקביל ל-Next.js ב-Vue?
Nuxt. כמו Next.js ל-React, הוא מוסיף מעל Vue ניתוב מבוסס קבצים, רינדור בצד השרת, יצירה סטטית ו-routes של שרת.