Vuejs: Xây dựng Vue Components một cách xịn xò hơn (P1)

Lại là trong lúc "rảnh rỗi" có lướt Gúc gồ vọc vạch thêm về Vuejs, tìm thấy mấy thứ hay ho như ở dưới đây, hy vọng là nó sẽ phục vụ nhiều cho nhu cầu công việc của các bạn, nếu không thì tìm hiểu thêm cũng khá là thú vị. Và ờm... lời khuyên là chỉ làm những lúc "rảnh rỗi" như mình thôi nhé :">

Hẳn là các bạn làm việc với Vuejs đã quá quen thuộc với các Components rồi phải không? Thế nhưng vẫn còn khá nhiều thứ có thể nghịch ngợm với các Components này mà chưa chắc các bạn đã biết 😄

Dưới đây là một số cách để xây dựng một Vue component, cõ lẽ là khác biệt hơn những cách bình thường mà bạn vẫn làm hàng ngày.

Nếu cảm thấy bài viết này hay thì hãy like, share and subscribe cho kênh của mình nhé 😉

Xây dựng Vue Component với vue-class-component

Đây là một package của Vue cho phép bạn định nghĩa các method một cách đơn giản hơn rất nhiều so với cách sử dụng Vue truyền thống. Trích README của vue-class-component:

  • methods có thể được khai báo trực tiếp trong class. Tức là không cần thông qua property methods: {} như trước nữa
  • Các thuộc tính Computed có thể được khai báo trực tiếp như một thuộc tính phụ trong class. Tức là cũng không cần thông qua property computed: {} như cách truyền thống
  • Các dữ liệu khởi tạo có thể được định nghĩa như một thuộc tính của class. Tức là cũng không cần thông của property method data() như các truyền thống
  • data, render và toàn bộ lifecycle của Vue đều có thể được định nghĩa trực tiếp như một phương thức của class, lưu ý một chút là bạn không thể gọi chúng trên instance và khi định nghĩa các phương thức của class thì tên method cần tránh các tên riêng ra.

Đây là một Single File Component Vue khi được xây dựng với vue-class-component. Dĩ nhiên là đừng quên cài đặt package này trước nhé:

$ yarn add vue-class-component

or

$ npm install -S vue-class-component
<template>
    <h1 @click="onClick">
        {{message}}
    </h1>
    <p>computed msg: {{computedMsg}}</p>
</template>

<script>
import Vue from 'vue';
import Component from 'vue-class-component';
    
@Component    
export default class App extends Vue {
    // properties
    message = 'Batman';
    
    // computed
    get computedMsg () {
        return 'computed ' + this.message
    }

    // methods
    onClick() {
      this.message = 'Bruce Wayne';
    }
};
</script>

Ngay từ giây đầu tiên nhìn thấy chắc hẳn rất nhiều dev React sẽ thấy nhột =)) Cũng phải công nhận là trông nó giống React quá.

Bạn có thể thấy ở đây tôi đang định nghĩa class App với method onClick() và thuộc tính message được khai báo trực tiếp mà không ảnh hưởng gì đến quá trình render của template, bù lại các code này khiến bộ code trông hướng đối tượng và dễ nhìn hơn rất nhiều.

So sánh với cách viết code truyền thống, bạn sẽ cần một phương thức data() để return về một object gồm các thuộc tính khởi tạo và một object methods để viết các function xử lý:

data() {
    return {
        message: "Batman"
    }
},
methods:{
    onClick() {
      this.message = "Bruce Wayne"
    }
}

Sử dụng vue-class-component làm code trông OOP hơn nhiều, mà hiệu quả vẫn tương tự

Nếu bạn đang sử dụng VS Code, bạn sẽ nhận được một vài thông báo lỗi ở dòng class App vì theo setup mặc định của VS Code không chấp nhận cách khai báo như vậy. Yên tâm là lỗi này không ảnh hưởng đến ứng dụng nhưng nếu không muốn VS Code hiển thị lỗi thì bạn có thể tạo một file jsconfig.json trong thư mục root của project như sau:

{
  "compilerOptions": {
    "experimentalDecorators": true
  }
}

Sau đó khởi động lại VS Code và lỗi đó sẽ biến mất. Ez

Định nghĩa Props với vue-property-decorator

Một cái hay nữa đến từ cộng đồng các dev Vue tài năng đó là package cùng tên ở trên.

Package này cho phép bạn định nghĩa các Props thực sự dễ dàng hơn, nó sẽ khiến class của bạn trông đơn giản hơn rất nhiều.

$ yarn add vue-property-decorator
$ npm install -S vue-property-decorator

Package này thậm chí còn include luôn cả vue-class-component ở trong nó, nên bạn chỉ cần cài mỗi package này là đủ.

Hãy thay đổi ví dụ ở trên một chút, giả sử message là một props được truyền vào component

<template>
    <h1 @click="onClick">
        {{message}}
    </h1>
    <p>computed msg: {{computedMsg}}</p>
</template>

<script>
import { Vue, Component, Prop } from 'vue-property-decorator'
    
@Component    
export default class App extends Vue {
    @Prop({default: 'Batman'}) message;
    
    // computed
    get computedMsg () {
        return 'I Am ' + this.message
    }

    // methods
    onClick() {
      this.message = 'Bruce Wayne';
    }
};
</script>

So sánh với code Vue truyền thống

export default {
  props: {
    message: {
      default: 'Batman'
    },
}

Không dám nói bên nào dễ hiểu hơn, dễ sử dụng hơn, nhưng cá nhân mình thích cách dùng @Prop hơn vì trông nó nguy hiểm hơn 😄

Ngoài ra, bạn còn các cách định nghĩa Prop khác như sau:

@Component
export default class YourComponent extends Vue {
    @Prop(Number) readonly propA!: number
    @Prop({ default: 'default value' }) readonly propB!: string
    @Prop([String, Boolean]) readonly propC!: string | boolean
}

Tương tự với:

export default {
  props: {
    propA: {
      type: Number
    },
    propB: {
      default: 'default value'
    },
    propC: {
      type: [String, Boolean]
    },
  }
}

Đơn giản hóa Components với Computted Setter

Computed chắc hẳn các bạn đã biết và làm việc nhiều với nó, nhưng GetterSetter của computed thì chắc là chưa nhiều người nghe qua. Đây là cách sử dụng computed đơn giản hàng ngày:

<template>
    <div>
        I Am {{ fullName }}
    </div>
</template>

<script>
data () {
  return {
    firstName: 'Tony',
    lastName: 'Stark'
  }
},

computed: {
  fullName () {
    return `${this.firstName} ${this.lastName}`
  }
}
</script>

Theo mặc định thì fullName khi được gọi ra ở template sẽ là một getter computed. Thế giả sử bây giờ tôi muốn set lại fullName thì sao??

Chúng ta hoàn toàn có thể làm nó thế này:

computed: {
  fullName: {
    get () {
      return `${this.firstName} ${this.lastName}`
    },

    set (fullName) {
      this.firstName = fullName.split(' ')[0]
      this.lastName = fullName.split(' ')[1]
    }
  }
}

Bây giờ bất cứ khi nào bạn đặt lại giá trị cho fullName (ví dụ: this.fullName = "Iron Man"), firstNamelastName sẽ được đặt lại giá trị tương ứng.

Kết hợp với vue-class-component

Dĩ nhiên package này cũng hỗ trợ luôn Computed Setter, các bạn chắc đã thấy getter trước đó rồi, còn đây là setter

<template>
    <p>computed msg: {{heIs}}</p>
    <button @click="onClick">Change Name</button>
</template>

<script>
import { Vue, Component, Prop } from 'vue-class-component'
    
@Component    
export default class MyComponent extends Vue {
    firstName = "Tony";
    lastName = "Stark";
    
    // computed
    get heIs () {
        return 'I Am ' + this.firstName + ' ' + this.lastName
    }
    
    set heIs(value) {
        this.firstName = fullName.split(' ')[0]
        this.lastName = fullName.split(' ')[1]
    }

    // methods
    onClick() {
      this.heIs = 'Iron Man';
    }
};
</script>

Tạm kết

Trên đây là một số phương pháp sử dụng các gói package bên ngài để giúp các dev Vue tạo ra các Components đơn giản và đem lại hiệu năng cao hơn mà mình tổng hợp được qua quá trình vọc vạch Google.

Có thể nhiều bạn đã biết rồi, có thể chưa. Nếu các bạn có ý kiến đóng góp thì vui lòng để dưới comment.

Bài viết sẽ tiếp tục với phần 2 cũng về chủ đề này nhưng với một cách tối ưu Component khác, rất mong sẽ được đón nhận.

Cám ơn đã theo dõi bài viết