Menu

React vs Vue: khác nhau thế nào, so sánh code song song

React và Vue đều là công cụ JavaScript để xây dựng giao diện người dùng từ các component. Chúng khác nhau ở cách viết markup (JSX và template), ở cách phản ứng với thay đổi (state bất biến và render lại so với ref reactive có thể thay đổi), và ở mức độ chính thức của hệ sinh thái.

Trang này có trình soạn thảo chạy trực tiếp. Sửa, chạy và xem đầu ra ngay lập tức.

React và Vue đều là công cụ JavaScript để xây dựng giao diện người dùng từ các component (React tự gọi mình là thư viện, còn Vue là progressive framework), và chúng có chung phần lớn ý tưởng: props truyền xuống, sự kiện truyền lên, state reactive, virtual DOM. Khác biệt thực tế là React viết markup bằng JSX và yêu cầu state được thay thế qua setter, còn Vue viết markup bằng template HTML bên trong single-file component và cho phép bạn thay đổi trực tiếp giá trị reactive. Đây là một bộ đếm trong React:

Và cùng bộ đếm đó dưới dạng single-file component của 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) thành ref(0), onClick thành @click, và {count} thành {{ count }}. Khác biệt dễ thấy là count++: Vue cho phép bạn thay đổi giá trị tại chỗ, và hệ thống reactivity của nó sẽ nhận ra. React cần setCount vì nó chỉ render lại khi bạn đưa cho nó một giá trị mới.

JSX và single-file component

Một component React là một hàm JavaScript trả về JSX. Điều kiện dùng && hoặc toán tử ba ngôi, danh sách dùng .map(), còn style đến từ bất cứ thứ gì bạn chọn (tệp CSS, CSS module, một framework utility).

Một component Vue thường là một tệp .vue có ba khối: <script setup> cho logic, <template> cho markup, và một khối <style scoped> tùy chọn với CSS chỉ áp dụng cho component đó. Template dùng các directive: v-if, v-for, v-model cho liên kết hai chiều với ô nhập, :prop để gắn một giá trị và @event để lắng nghe sự kiện. Template giúp markup dễ đọc với bất kỳ ai biết HTML; JSX cho bạn toàn bộ sức mạnh của JavaScript ngay trong markup. Vue cũng có thể dùng JSX còn React không dùng được template, nhưng phần lớn code ở mỗi bên đều theo cách mặc định của nó.

Đây là một danh sách có bộ lọc, tính năng thứ hai để so sánh.

Thử gõ xyz để thấy thông báo khi không có kết quả, rồi xóa đi. Phiên bản 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 thay cho cặp value và onChange, còn computed thay cho biến thông thường. Trong React, visible được tính lại ở mọi lần render vì hàm component chạy lại; trong Vue, computed lưu cache và chỉ tính lại khi query thay đổi. Cả hai đều dùng key để phân biệt các mục trong danh sách.

Mô hình reactivity

Đây là khác biệt sâu sắc nhất giữa hai bên.

React: state bất biến và render lại. State là một bản chụp. Bạn gọi setter với một giá trị mới, React chạy lại hàm component, so sánh JSX mới với JSX cũ và cập nhật DOM. React so sánh giá trị bằng Object.is, nên sửa một object hay mảng tại chỗ rồi truyền lại chính nó thì trông như không có gì thay đổi.

Nhấn "push() in place" và màn hình không thay đổi gì, vì mảng vẫn là cùng một object. Sau đó nhấn "New array": lần render hiện cả pushed, vì thao tác sửa trước đó thực sự đã xảy ra, chỉ là React không có lý do để xem lại. Trang useState giải thích kỹ mẫu này.

Vue: giá trị reactive có thể thay đổi. Một ref hoặc object reactive ghi lại ai đang đọc nó (ref thông qua getter .value, object reactive thông qua một proxy). Khi bạn ghi vào nó, Vue biết chính xác những giá trị computed, watcher và phần template nào phụ thuộc vào nó và chỉ cập nhật những phần đó. Trong Vue, items.value.push('pushed') sẽ cập nhật màn hình. Bạn viết ít thủ tục hơn, đổi lại bạn mất đi sự đảm bảo rằng một giá trị không bao giờ bị thay đổi sau lưng bạn.

Không mô hình nào nhanh hơn đến mức tạo khác biệt với các ứng dụng thông thường. React có thể chạy nhiều code component hơn cho mỗi thay đổi và dựa vào memo hóa (viết tay, hoặc qua React Compiler) để bỏ qua công việc; Vue theo dõi dependency lúc chạy nên mặc định đã bỏ qua phần công việc đó.

Composition API và hook

Composition API của Vue 3 và hook của React giải quyết cùng một vấn đề: gom state và logic liên quan lại với nhau và tái sử dụng chúng giữa các component. Vue gọi các hàm tái sử dụng này là composable (useMouse()), React gọi là custom hook (useMouse()). Quy tắc khác nhau vì thời điểm code chạy khác nhau.

  • Khi nào chạy. setup của Vue chạy một lần khi component được tạo. Hàm component của React chạy ở mọi lần render, và các hook bên trong chạy cùng với nó.
  • Quy tắc thứ tự. React khớp hook theo thứ tự gọi, nên bạn không thể gọi chúng trong điều kiện hay vòng lặp. Vue không có quy tắc này cho ref và computed, vì setup chỉ chạy một lần.
  • Dependency. Effect và memo của React liệt kê dependency trong một mảng do bạn tự duy trì. watchEffect và computed của Vue tự động theo dõi những gì chúng đọc.
  • Giá trị cũ. Một callback trong React có thể giữ lại giá trị state cũ từ một lần render trước (lỗi kinh điển với setInterval). Một callback trong Vue đọc count.value tại thời điểm gọi và luôn thấy giá trị hiện tại.

Mô hình của React khiến mỗi lần render là một hàm thuần của props và state, dễ kiểm thử và dễ suy luận. Mô hình của Vue loại bỏ cả một nhóm lỗi liên quan đến mảng dependency. Lập trình viên đã biết một bên thường học bên còn lại khá nhanh.

Hệ sinh thái

ReactVue
MarkupJSXTemplate HTML trong tệp .vue (JSX tùy chọn)
Cập nhật stateThay thế bằng setter, rồi render lạiThay đổi giá trị reactive, các phần phụ thuộc tự cập nhật
Tái sử dụng logicCustom hookComposable
Giá trị suy raTính trong lúc render, useMemocomputed (có cache)
Liên kết hai chiều với ô nhậpvalue cùng onChangev-model
CSS theo phạm viKhông có sẵn (CSS module, thư viện)Có sẵn <style scoped>
Định tuyếnReact Router, TanStack Router, frameworkVue Router (chính thức)
State toàn cụcContext, Zustand, Redux ToolkitPinia (chính thức)
Framework full-stackNext.js, React Router ở chế độ frameworkNuxt
Ứng dụng di độngReact NativeKhông có lựa chọn chính thức (Capacitor, NativeScript-Vue)
Công cụ buildVite hoặc một frameworkVite
Đơn vị duy trìMeta và cộng đồngMột nhóm phát triển cốt lõi độc lập và cộng đồng

Quy luật trong bảng trên: nhóm cốt lõi của Vue duy trì router, store và devtools cùng nhau, nên một dự án Vue có lựa chọn mặc định rõ ràng cho từng thứ. React để những thứ đó cho cộng đồng, nghĩa là bạn có nhiều lựa chọn hơn và cũng phải đưa ra nhiều quyết định hơn. Vite, công cụ build quen thuộc cho dự án mới ở cả hai bên, do chính người tạo ra Vue khởi xướng.

Độ khó khi học

Vue thường là điểm khởi đầu nhẹ nhàng hơn. Template đọc giống HTML bạn đã biết, v-model loại bỏ phần code lặp lại của ô nhập có kiểm soát, và một giá trị reactive sẽ cập nhật màn hình khi bạn thay đổi nó. React yêu cầu học JSX và thói quen cập nhật bất biến ngay từ đầu, và trang JSX là thứ đầu tiên phần lớn mọi người cần.

Sau phần cơ bản, khoảng cách thu hẹp lại. Vue có các khái niệm riêng (ref và object reactive, .value trong script nhưng không có trong template, watcher), còn React có effect, memo hóa và Rules of Hooks. Tin tuyển dụng ở khu vực của bạn là tiêu chí quyết định hữu ích hơn cú pháp.

Khi nào chọn bên nào

Chọn React khi:

  • Bạn muốn có nhiều lựa chọn thư viện và component từ cộng đồng, hoặc dự định xây dựng ứng dụng di động native bằng React Native.
  • Bạn thích giữ logic và markup trong cùng một hàm JavaScript và muốn dùng một framework như Next.js.
  • Đội của bạn coi trọng việc cập nhật rõ ràng, bất biến, giúp dễ lần theo từng lần render.

Chọn Vue khi:

  • Bạn muốn các công cụ chính thức, đồng bộ cho định tuyến và state, và ít quyết định phải đưa ra hơn.
  • Đội của bạn có designer hoặc lập trình viên back-end đã quen với template HTML.
  • Bạn đang thêm tính tương tác vào các trang render phía máy chủ có sẵn: Vue có thể được nhúng vào trang bằng một thẻ script rồi mở rộng dần từ đó.

Cả hai đều đã trưởng thành và được các công ty mọi quy mô dùng trong môi trường production, và những khái niệm bạn học ở bên này (component, props, state suy ra, danh sách có key) đều áp dụng ngay được cho bên kia.

Câu hỏi thường gặp

Vue có dễ học hơn React không?

Nhiều người mới bắt đầu thấy Vue dễ hơn lúc đầu, vì template trông như HTML thuần và việc thay đổi một giá trị reactive (count.value++) sẽ cập nhật màn hình mà không cần setter. React yêu cầu bạn học JSX và quy tắc state phải được thay thế, không được sửa trực tiếp. Sau vài tuần đầu, độ khó của hai bên là tương đương.

React hay Vue tốt hơn?

Không bên nào thắng tuyệt đối. React để việc định tuyến và quản lý state cho các thư viện cộng đồng và có React Native cho di động. Vue có router, store và devtools chính thức được duy trì cùng nhau, cùng với template mà nhiều người thấy dễ đọc hơn. Hãy chọn công nghệ mà đội của bạn hoặc thị trường việc làm đang dùng.

Composition API của Vue khác hook của React thế nào?

Cả hai đều gom logic có state vào các hàm tái sử dụng được. setup của Vue chạy một lần cho mỗi component và tự động theo dõi dependency, nên không có mảng dependency và không có closure cũ. Hàm component của React chạy ở mọi lần render, nên hook phải được gọi theo cùng thứ tự mỗi lần và effect phải liệt kê dependency của nó.

Vue có dùng JSX không?

Vue hỗ trợ JSX qua một plugin, nhưng phần lớn code Vue dùng template HTML trong single-file component (tệp .vue). React dùng JSX gần như ở mọi nơi.

Next.js của Vue là gì?

Nuxt. Giống như Next.js với React, Nuxt bổ sung định tuyến theo tệp, render phía máy chủ, tạo trang tĩnh và server route cho Vue.

Hình minh họa các ngôn ngữ lập trình của Coddy

Học lập trình cùng Coddy

Bắt đầu