So sánh ReactJS và VueJS - Hiệp 1: create-react-app vs create-vue

# So sánh ReactJS và VueJS<br>Hiệp 1: create-react-app vs create-vue
Dựa vào một số kinh nghiệm với những project ReactJS và VueJS đã tham gia, tôi có một số lưu ý muốn viết ra để chia sẻ.
Lần này, chúng ta sẽ bàn chủ yếu về khác nhau giữa create-react-app và create-vue.
Mã nguồn tham khảo <sup>[1]</sup> được ghi chú trong danh mục tham khảo bên dưới. 

**1. Về cài đặt:** Chỉ so sánh điểm khác nhau.
<table>
  <thead>
    <tr>
      <th>ReactJS</th><th>VueJS</th>
    </tr>
  </thead>
  <tr>
    <td>Lệnh cài đặt: <br>`npx create-react-app react-app --template typescript`</td><td>Lệnh cài đặt: <br>`npm create vue@3`</td>
  </tr>
  <tr>
    <td>Sử dụng react-scripts bên trong.</td><td>Sử dụng Vite bên trong.</td>
  </tr>
  <tr>
    <td>Không có option để cài đặt thư viện router, phải dùng npm để cài đặt sau.</td><td>Có option để cài đặt thư viện router.</td>
  </tr>
  <tr>
    <td>Không có option để cài đặt thư viện quản lý state (như Redux), phải dùng npm để cài đặt sau.</td><td>Có option để cài đặt thư viện quản lý state (như Pinia).</td>
  </tr>
  <tr>
    <td>Không có option để cài đặt thư viện test E2E (như Cypress).</td><td>Có option để cài đặt.</td>
  </tr>
  <tr>
    <td>Thông thường hay sử dụng CSS-in-JS. Dùng npm để cài đặt styled-component. Styled-component không có hiện tượng xung đột class CSS.</td><td>Thông thường hay dùng CSS scoped, hoặc CSS module. CSS scoped/module có hiện tượng xung đột class CSS <sup>[2]</sup>.</td>
  </tr>
  <tr>
    <td>Có hỗ trợ sẵn PostCSS.</td><td>Có hỗ trợ, nhưng nếu muốn sử dụng thì phải thêm config của PostCSS.</td>
  </tr>
</table>

**2. Về cú pháp:**　Chỉ so sánh điểm khác nhau.
<table>
  <thead>
    <tr>
      <th>ReactJS</th><th>VueJS</th>
    </tr>
  </thead>
  <tr>
    <td>Có thể định nghĩa component bằng class hoặc function. Class component và function component có thể sử dụng chung với nhau. Trong class component thì không thể sử dụng hook của function component.</td><td>Có thể dùng Options API và Composition API để định nghĩa component. Options component và Composition component không thể dùng chung với nhau. Vite hiện tại chỉ support Composition component. Trong Options component có thể sử dụng một phần hook của Composition.</td>
  </tr>
  <tr>
    <td>Class component có thể kế thừa bằng cách extend class, hoặc dùng hình thức HOC <sup>[3]</sup>. Class có thể kế thừa nên dễ làm các component phức tạp cùng chia sẻ các xử lý như validation.</td><td>Component chỉ có thể kế thừa bằng hình thức HOC.</td>
  </tr>
  <tr>
    <td>Trong file .jsx/tsx, có thể định nghĩa nhiều component. Có thể tạo được các private component (component không muốn export/chia sẻ).</td><td>Trong file .vue, chỉ có thể định nghĩa 1 component.<br><strong>※Tất cả component đều phải ghi ra file nên cần phải có rule để chia sẻ trong nhóm phát triển.</strong></td>
  </tr>
  <tr>
    <td>Không hỗ trợ dynamic component nhưng có thể dùng Javascript để thay đổi component. Có thể tạo component linh động. Trong component có thể tạo component khác <sup>[4]</sup>.</td><td>Có hỗ trợ dynamic component <sup>[5]</sup>. Khó tạo component 1 cách linh động. Trong Options component, có thể dùng hàm getCurrentInstance để tạo 1 Options component khác, nhưng trong Composition component, không thể sử dụng hàm getCurrentInstance <sup>[6]</sup>.</td>
  </tr>
  <tr>
    <td>Trong template sử dụng hàm của Javascript. Ví dụ: for, if v.v.. có thể thao tác bằng Javascript.</td><td>Trong template sử dụng directive. Ví dụ: for, if v.v.. thì tao tác bằng v-for, v-if. Cần phải học API của directive để có thể sử dụng thông thạo.</td>
  </tr>
  <tr>
    <td></td><td>Trong trường hợp sử dụng Typescript, để tạo component, nếu là Options thì phải dùng hàm defineComponent, nếu là Composition thì phải dùng hàm defineProps.</td>
  </tr>
</table>

**3. Về hiệu năng:**
- Tôi đã làm thử 1 thí nghiệm nho nhỏ để đo thử tốc độ vẽ DOM.
- Thời điểm đo là từ khi trình duyệt bắt đầu định hướng cho tới khi hoàn tất tải DOM (sau khi app đã mount). Mã nguồn đã được build xong rồi mới đo.
- Dùng cùng 1 trình duyệt (Chrome) ở private mode, xoá cache mỗi lần thực thi.
- 3 component để đo là list (ul).
    - List1: list 1 lớp, 10 mục con (li).
    - List2: list 2 lớp, 100 mục con (li).
    - List3: list 3 lớp, 1000 mục con (li).
- Kết quả đo như bên dưới. Giá trị có thể thay đổi theo mỗi lần thí nghiệm, nhưng để hình dung, tôi đã lấy giá trị trung bình.
<table>
  <thead>
    <tr>
      <th></th><th>ReactJS</th><th>VueJS</th>
    </tr>
  </thead>
  <tr>
    <td>List1 (1 lớp)</td><td>317 ms</td><td>279 ms</td>
  </tr>
  <tr>
    <td>List1 (2 lớp)</td><td>340 ms</td><td>393 ms</td>
  </tr>
  <tr>
    <td>List1 (3 lớp)</td><td>344 ms</td><td>1724 ms</td>
  </tr>
</table>

- Từ kết quả trên, có thể có vài hình dung về vẽ DOM.
    - Trường hợp số lớp của component ít, VueJS nhanh hơn ReactJS một chút.
    - Số lớp của component càng nhiều lên thì ReactJS nhanh hơn VueJS.

**4. Về quản lý state:**
<table>
  <thead>
    <tr>
      <th>ReactJS</th><th>VueJS</th>
    </tr>
  </thead>
  <tr>
    <td>State của React mặc định là chỉ so sánh lớp thuộc tính đầu tiên (shallow compare) của object, nếu dùng PureComponent thì dùng "===" để so sánh. Vì Redux so sánh state là dùng "===" để so sánh, nên khi cập nhật state thì cần tạo mới object. <br><strong>※ Vì có hiện tượng component con được render nhiều lần, nên nếu ảnh hưởng đáng kể đến hiệu năng thì cần sử dụng hook của React như useMemo<sup> [8] </sup>, hoặc reselect của Redux.</strong></td><td>Mặc định nếu thuộc tính của state là nested object thì so sánh toàn bộ nested object, nên để cập nhật state thì trực tiếp cập nhật thuộc tính của state.<br><strong>※ Trường hợp cấu trúc của state đơn giản thì không vấn đề gì, nhưng nếu cấu trúc của state quá phức tạp (ví dụ: list có lượng lớn data của API response, data có quá nhiều lớp con) thì vì ảnh hưởng đến hiệu năng nên cần phải xem xét sử dụng shallowReactive <sup>[7]</sup>.</strong></td>
  </tr>
  <tr>
    <td>Nếu là class thì dùng thuộc tính của state, nếu là function thì dùng hook useState để quản lý state của component.</td><td>Nếu là Options thì dùng thuộc tính data, nếu là Composition thì dùng định nghĩa biến để quản lý state của component.</td>
  </tr>
  <tr>
    <td>Thường dùng Redux. Gần đây có Recoil. Recoil là thư viện có tính gắn chặt với các tính năng mới nhất của React, chú trọng về xử lý bất đồng bộ (như gửi request bất đồng bộ v.v..). Không cần nâng cấp từ Redux qua Recoil. Redux hỗ trợ cả class và function component. Recoil không hỗ trợ class component.</td><td>Thường dùng Vuex. Gần đây có Pinia. Pinia là phiên bản tiếp theo của Vuex nên cần phải nâng cấp từ Vuex qua Pinia. Vuex/Pinia hỗ trợ cả Options và Composition component.</td>
  </tr>
  <tr>
    <td>Redux phải sử dụng cùng với react-redux.</td><td>Vuex/Pinia thì sử dụng độc lập.</td>
  </tr>
  <tr>
    <td>Cập nhật state của Redux thì chỉ có thể thông qua action (dispatch).</td><td>Vuex thì dùng cả mutation và action để cập nhật state, nhưng Pinia thì đã bỏ mutation, chỉ dùng action để cập nhật state.</td>
  </tr>
  <tr>
    <td>Trong middleware của Redux, không thể trực tiếp cập nhật state, có thể dừng việc cập nhật state tiếp theo.</td><td>Trong plugin của Vuex/Pinia, có thể trực tiếp cập nhật state, không thể dừng việc cập nhật state tiếp theo.</td>
  </tr>
  <tr>
    <td>Có thể dùng các thư viện thông dụng như redux-saga, redux-observable v.v.. để điều khiển data flow (việc phát action).</td><td>Hiện tại chưa có thư viện thông dụng.</td>
  </tr>
  <tr>
    <td>Có thể dùng thư viện thông dụng redux-persist để quản lý việc nâng cấp data cho local storage.</td><td>Hiện tại chưa có thư viện thông dụng.</td>
  </tr>
</table>

**5. So sánh của ChatGPT:**
- Ở đây xin viết lại y chang câu trả lời của ChatGPT.
> Hãy so sánh ReactJS và VueJS.
>
> ReactJS và VueJS đều là các framework frontend JavaScript phổ biến, có thể được sử dụng để xây dựng các ứng dụng web động. Dưới đây là một số so sánh giữa hai framework này:
>
> 1. Cú pháp và cách thức hoạt động: VueJS sử dụng cú pháp gần giống với HTML và CSS, trong khi ReactJS sử dụng JSX để viết mã HTML trong JavaScript. VueJS cũng có một số tính năng như Directive, về cơ bản giống với các thuộc tính của HTML, trong khi ReactJS tập trung vào các Components và Props để tạo giao diện.
>
> 2. Khả năng mở rộng: Cả ReactJS và VueJS đều có khả năng mở rộng, tuy nhiên cách thức triển khai khác nhau. ReactJS sử dụng Redux hoặc Flux để quản lý trạng thái của ứng dụng, trong khi VueJS sử dụng Vuex.
>
> 3. Hiệu suất: ReactJS được đánh giá cao về hiệu suất, đặc biệt khi xử lý các ứng dụng lớn. VueJS cũng khá nhanh, nhưng tốc độ không thể so sánh với ReactJS.
>
> 4. Tài liệu và cộng đồng hỗ trợ: ReactJS có cộng đồng lớn và đầy đủ tài liệu hướng dẫn, trong khi VueJS cũng có cộng đồng khá lớn, nhưng tài liệu không nhiều bằng ReactJS.
>
> 5. Sự lựa chọn của các công ty: ReactJS được sử dụng rộng rãi bởi các công ty lớn như Facebook, Instagram, Dropbox, Netflix, Airbnb... Tuy nhiên, VueJS cũng có một số khách hàng đáng chú ý như Alibaba, Xiaomi, Adobe, Behance.
>
> Tóm lại, cả ReactJS và VueJS đều là các framework JavaScript phổ biến và có khả năng mở rộng. Có thể chọn bất kỳ framework nào tùy thuộc vào nhu cầu và tính năng của ứng dụng.

### Danh mục tham khảo:
1. [Mã nguồn tham khảo](https://github.com/nguyenrazona/compare-react-vue)
2. [Hiện tượng xung đột class của VueJS CSS scoped](https://qiita.com/mascii/items/623d4c97c3f95e6984c0#2%E5%80%8B%E3%81%AE-data-v-xxxxxxxx-%E5%B1%9E%E6%80%A7%E3%81%AE%E4%BB%98%E4%B8%8E)
3. [HOC](https://ja.reactjs.org/docs/higher-order-components.html)
4. [Ví dụ về tạo component linh động trong ReactJS](https://github.com/nguyenrazona/compare-react-vue/blob/main/1_react-app/src/App.tsx#L31)
5. [Dynamic component của VueJS](https://vuejs.org/guide/essentials/component-basics.html#dynamic-components)
6. [Tạo component linh động trong VueJS](https://stackoverflow.com/questions/72031321/dynamically-create-a-component-in-vue-js)
7. [Về shallowReactive của VueJS](https://vuejs.org/guide/best-practices/performance.html#reduce-reactivity-overhead-for-large-immutable-structures)
8. [React useMemo](https://reactjs.org/docs/hooks-faq.html#how-to-memoize-calculations)

*※ Bài viết này chỉ so sánh dựa trên phiên bản hiện tại của các thư viện. Trong tương lai có thể sẽ cần có cập nhật.*