Là một lập trình viên đã từng làm việc với nhiều framework front-end phổ biến như React, Angular và Vue, tôi nhận ra rằng mỗi framework có những ưu điểm và nhược điểm riêng. Trong bài viết này, tôi sẽ phân tích lý do tại sao Angular hoặc Vue có thể là lựa chọn tốt hơn React cho dự án web tiếp theo của bạn, đặc biệt khi bạn cần một ứng dụng có cấu trúc và khả năng mở rộng tốt.

1. Mẫu (Template) 

Điểm khác biệt chính giữa React, Angular và Vue nằm ở cách thức xử lý giao diện người dùng. React sử dụng JSX, cho phép bạn kết hợp logic JavaScript trực tiếp vào mã HTML. Mặc dù điều này mang lại sự linh hoạt cao, nhưng nó cũng có thể dẫn đến code khó đọc và khó bảo trì, đặc biệt khi ứng dụng của bạn trở nên phức tạp.

Ngược lại, Angular và Vue sử dụng hệ thống mẫu riêng biệt, tách biệt logic khỏi giao diện. Điều này giúp code dễ đọc và dễ bảo trì hơn, đồng thời cũng tạo điều kiện cho việc tái sử dụng code hiệu quả hơn. 

Hãy cùng theo dõi ví dụ bên dưới để bạn có thể hiểu rõ hơn:

React JSX:

return (  
  <div>  
    {array.map(item => {  
      if (condition) {  
        return <p>{item}</p>;  
      } else {  
        return <span>{item}</span>;  
      }  
    })}  
  </div>  
); 

Angular Template:

<div *ngFor="let item of array">  
  <p *ngIf="condition; else other">{{ item }}</p>  
  <ng-template #other><span>{{ item }}</span></ng-template>  
</div>

Vue Template:

<div v-for="item in array">
<p v-if="condition">{{ item }}</p>
<span v-else>{{ item }}</span>
</div>

2. Liên kết Kiểm soát Biểu mẫu (Binding Form Controls)

Angular và Vue cung cấp các cách đơn giản để liên kết các kiểm soát biểu mẫu (Binding Form Controls), giúp việc quản lý dữ liệu biểu mẫu với nhiều trường trở nên dễ dàng. Hãy cùng tạo một đối tượng biểu mẫu với bốn trường: ô nhập văn bản, nút radio, hộp kiểm và danh sách lựa chọn.

Angular:

@Component({
  selector: 'app-form',
  template: `
    <form>
      <input type="text" [(ngModel)]="formData.text" placeholder="Text Input">
      <br>
      <input type="radio" [(ngModel)]="formData.radio" value="option1"> Option 1
      <input type="radio" [(ngModel)]="formData.radio" value="option2"> Option 2
      <br>
      <input type="checkbox" [(ngModel)]="formData.checkbox"> Checkbox
      <br>
      <select [(ngModel)]="formData.select">
        <option value="option1">Option 1</option>
        <option value="option2">Option 2</option>
      </select>
    </form>
  `,
})
export class FormComponent {
  formData = {
    text: '',
    radio: '',
    checkbox: false,
    select: '',
  };
}

Vue:

<template>
  <form>
    <input type="text" v-model="formData.text" placeholder="Text Input">
    <br>
    <input type="radio" v-model="formData.radio" value="option1"> Option 1
    <input type="radio" v-model="formData.radio" value="option2"> Option 2
    <br>
    <input type="checkbox" v-model="formData.checkbox"> Checkbox
    <br>
    <select v-model="formData.select">
      <option value="option1">Option 1</option>
      <option value="option2">Option 2</option>
    </select>
  </form>
</template>

<script>
export default {
  data() {
    return {
      formData: {
        text: '',
        radio: '',
        checkbox: false,
        select: '',
      },
    };
  },
};
</script>

React:

const FormComponent = () => {
  const [formData, setFormData] = useState({
    text: '',
    radio: '',
    checkbox: false,
    select: '',
  });

  const handleChange = (e) => {
    const { name, value, type, checked } = e.target;
    setFormData({
      ...formData,
      [name]: type === 'checkbox' ? checked : value,
    });
  };

  return (
    <form>
      <input type="text" name="text" value={formData.text} onChange={handleChange} placeholder="Text Input" />
      <br />
      <input type="radio" name="radio" value="option1" checked={formData.radio === 'option1'} onChange={handleChange} /> Option 1
      <input type="radio" name="radio" value="option2" checked={formData.radio === 'option2'} onChange={handleChange} /> Option 2
      <br />
      <input type="checkbox" name="checkbox" checked={formData.checkbox} onChange={handleChange} /> Checkbox
      <br />
      <select name="select" value={formData.select} onChange={handleChange}>
        <option value="option1">Option 1</option>
        <option value="option2">Option 2</option>
      </select>
    </form>
  );
};

Trong React, nếu không sử dụng các thư viện như Formik hay React Hook Form, việc quản lý trạng thái biểu mẫu (form state) đòi hỏi bạn phải thiết lập các biến trạng thái bằng useState và viết các hàm xử lý (handler function) để cập nhật trạng thái mỗi khi dữ liệu trong các trường biểu mẫu thay đổi. Cách làm này có thể dẫn đến nhiều đoạn mã lặp lại (boilerplate code) và tăng độ phức tạp, đặc biệt với các biểu mẫu có nhiều trường. Mặc dù các thư viện về biểu mẫu cung cấp các tính năng xử lý biểu mẫu nâng cao, việc tích hợp chúng vào dự án buộc bạn phải thiết lập và học hỏi thêm rất nhiều.

Khả năng xử lý biểu mẫu tích hợp sẵn của Angular và Vue cung cấp một cách tiếp cận đơn giản và liền mạch hơn, cho phép developer tập trung vào việc xây dựng ứng dụng mà không cần phụ thuộc thêm vào các thư viện khác.

3. Truy cập các thành phần con (child component)

Trong các framework xây dựng giao diện người dùng (front-end), ViewChild của Angular, refs của Vue và useImperativeHandle của React đều là những cơ chế để tương tác với các thành phần con (child component). Tuy nhiên Angular và Vue cung cấp cách tiếp cận gọn gàng và trực quan hơn so với useImperativeHandle của React, ví dụ:

Angular:

@Component({
  selector: 'app-parent',
  template: `
    <app-child #child></app-child>
    <button (click)="callChildMethod()">Call Child Method</button>
  `,
})
export class ParentComponent {
  @ViewChild('child') childComponent: ChildComponent;

  callChildMethod() {
    this.childComponent.someMethod();
  }
}

Vue:

<template>
  <div>
    <child ref="child"></child>
    <button @click="callChildMethod">Call Child Method</button>
  </div>
</template>

<script>
import Child from './Child.vue';

export default {
  components: {
    Child,
  },
  methods: {
    callChildMethod() {
      this.$refs.child.someMethod();
    },
  },
};
</script>

React:

const ChildComponent = forwardRef((props, ref) => {
  useImperativeHandle(ref, () => ({
    someMethod() {
      // Method logic
    },
  }));

  return <p>I am a child</p>;
});

const ParentComponent = () => {
  const childRef = useRef(null);

  // Access child component's method
  const handleButtonClick = () => {
    childRef.current.someMethod();
  };

  return (
    <div>
      <ChildComponent ref={childRef} />
      <button onClick={handleButtonClick}>Call Child Method</button>
    </div>
  );
};

Trong React, thành phần chức năng không cung cấp các "phương thức" như thành phần lớp trong Angular hoặc Vue. Trong Vue, bạn có thể truy cập các phương thức con thông qua thuộc tính "phương thức". Để làm điều tương tự trong React mà không dùng hook useImperativeHandle (vì hook này kém rõ ràng hơn và cần phải bọc thành phần con bằng hàm forwardRef), bạn cần có một cách tiếp cận đơn giản hơn. Trong khi Angular và Vue cho phép truy cập phương thức con mà không cần thay đổi thành phần con, React yêu cầu thiết lập bổ sung để đạt được chức năng tương tự.

Ngoài ra, tôi muốn nói về Vue. Composition API là một công nghệ tương đối mới và việc truy cập các thành phần con có hơi khác một chút so với cách tiếp cận truyền thống mà tôi đã đề cập. Tuy nhiên, tôi nghĩ rằng không phải tất cả các nhóm đều sử dụng cách tiếp cận truyền thống để triển khai Composition API trong các dự án của họ.

Tôi đã đưa ra ba lý do tại sao, theo ý kiến của tôi, bạn nên chọn Angular hoặc Vue thay vì React. Cuối bài viết, tôi muốn nói về kích thước của gói sản phẩm cuối cùng của ba framework này. Một ứng dụng web được tối ưu hóa và hoạt động mượt mà trên các thiết bị và trình duyệt khác nhau, mang lại trải nghiệm người dùng tốt. Điều này rất quan trọng cho doanh nghiệp.

Khi nói đến kích thước gói, điều cần thiết là phải xem xét tác động đến hiệu suất và trải nghiệm người dùng. Dưới đây là cách kích thước gói của từng framework có thể ảnh hưởng đến dự án của bạn:

  • React: Mặc dù React có kích thước gói nhỏ hơn cho các ứng dụng đơn giản  như các dự án "Hello World" (30-100 KB), nhưng lợi thế về kích thước gói của React giảm dần theo độ phức tạp của ứng dụng. Với một ứng dụng cửa hàng trực tuyến đầy đủ tính năng, kích thước gói của React có thể dao động từ 500 KB đến 2 MB hoặc hơn, tương tự như Angular và Vue. Vì vậy, nếu bạn ưu tiên kích thước gói nhỏ, React có thể không mang lại lợi thế lớn so với Vue hoặc Angular.

  • Angular: Kích thước gói của Angular nhìn chung lớn hơn so với React, chủ yếu là do các tính năng framework toàn diện của nó. Đối với một ứng dụng "Hello World" cơ bản, kích thước gói có thể dao động từ 100 KB đến 300 KB, trong khi đối với một ứng dụng cửa hàng trực tuyến, nó có thể nằm trong khoảng từ 1 MB đến 3 MB. Bất chấp kích thước lớn hơn, các tính năng tối ưu hóa tích hợp của Angular như biên dịch Ahead-of-Time (AOT) và lazy loading có thể giúp giảm thiểu tác động này.

  • Vue: Vue tạo ra sự cân bằng giữa tính linh hoạt của React và các tính năng toàn diện của Angular, dẫn đến kích thước gói thường nằm giữa hai framework này. Đối với một ứng dụng "Hello World", kích thước gói của Vue có thể dao động từ 50 KB đến 150 KB, trong khi đối với một ứng dụng cửa hàng trực tuyến, nó có thể vào khoảng 500 KB đến 1.5 MB. 

Lời kết

Tóm lại, điều quan trọng là phải ghi nhận những đóng góp của các nhà phát triển React và những người tạo ra thư viện React. Tuy nhiên, theo kinh nghiệm của tôi, xây dựng một ứng dụng React mà không có sự hướng dẫn của các nhà phát triển có kinh nghiệm có thể gặp nhiều khó khăn. Tính linh hoạt của React có thể dẫn đến những sai lầm nếu không được quản lý đúng cách, ví dụ: các nhà phát triển thiếu kinh nghiệm có thể gặp khó khăn trong việc tạo ra các ứng dụng React có thể bảo trì và mở rộng. Mặt khác, các framework như Vue và Angular cung cấp một cách tiếp cận có cấu trúc hơn với các khái niệm và quy ước nghiêm ngặt. Các framework này hướng dẫn các nhà phát triển theo hướng thực tiễn tốt nhất, giúp giảm thiểu các nhược điểm phổ biến, và xây dựng các ứng dụng mạnh mẽ trở nên dễ dàng hơn ngay cả đối với những người ít kinh nghiệm.

Cuối cùng, việc lựa chọn giữa React, Vue và Angular phụ thuộc vào nhiều yếu tố như yêu cầu của dự án, chuyên môn của đội ngũ và sở thích cá nhân. Tuy nhiên, đối với các nhà phát triển muốn một cách tiếp cận có hướng dẫn và có cấu trúc hơn, Vue và Angular có thể mang lại một quá trình học tập dễ dàng và một môi trường có nhiều sự hỗ trợ để xây dựng các ứng dụng phức tạp.

Nguồn: Roman Ismagilov

VietnamWorks inTECH