vuejs-design-pattern-clean-code

Clean code với Vuejs Anti pattern – Phần 1

Bắt đầu với lí do tại sao lại có chuỗi bài Vuejs Anti Pattern.

Trong quá trình lead một team làm việc chủ yếu với Nuxtjs và Typescript. Bản thân tôi thấy rất nhiều member bị dính những con bug khá khoai (đại loại như out of control)

Sau khi bỏ time điều tra, hầu hết do các bạn code không theo một quy củ nào. Cũng không có tài liệu nào cho biết cách làm A thì tốt hơn cách làm B. Hoặc cách làm C sẽ gây khó khăn sau này khi maintain

Chính vì vậy tui viết chuối bài Vuejs Anti Pattern liệt kê những pattern cần tránh khi làm việc với Vuejs

Có 2 phần nha, phần này là phần 1

Bắt đầu thôi nào!

1. Communication – Giao tiếp giữa các component

Communication là giao tiếp, trong Vuejs Anti Pattern thì pattern này khá phổ biến và cũng được biết tới rất nhiều. Hiện nay có vẻ không còn nhiều người còn dính pattern này trong quá trình làm

Giả sử ta cố 2 component, một là Todo List và thứ hai là Todo Item. Component Todo List sẽ render một loạt các component Todo Item. Lúc này việc giao tiếp giữa các component sẽ trở nên quan trọng.

Thông thường Vue sẽ cho phép ta access được tới $parent (component cha) và $child (component) con. Bằng cách này:

BAD  

export default {
  props: ['todo'],
  methods: {
    completeTodo(todo) {
      this.$parent.$options.methods.completeTodo(todo);
    }
  }
}

Cách làm này có một cái dở, 2 component cha con bị dính lấy nhau. Component cha mặc định sẽ phải có method completeTodo

Với emit, giao tiếp giữa 2 component cha con trở nên đơn giản và gọn gàng hơn nhiều

GOOD

methods: {
  completeTodo(todo) {
    this.$emit('completeTodo', todo)
  }
}

Pattern này khá phổ biến và cũng thường xuyên được áp dụng. Anh em có thể đã khá quen với pattern này rồi.

2. Children mutating props – Thay đổi props

Mục đích chính của pattern này là tuyệt đối không thay đổi props khi đã đưa qua component con

Props should be considered the source of truth when passed down to a component and thus, change the value from within a child component is typically bad practice

Props nên được cân nhắc để không thay đổi khi đã gửi qua component, thay đổi props khi gửi qua child component cũng là bad practice

Thay đổi props

BAD

methods: {
  completeTodo(todo) {
    this.todo = [{id: 1, name: 'Do the dishes.'}];
    this.$emit('completeTodo', todo)
  }
}

Component props tuyệt đối không nên thay đổi, chỉ được sử dụng

GOOD

export default {
  props: {
    age: {
      type: Number,
    }
  },
  data() {
    return {
      personAge: this.age
    }
  },
}

Nếu muốn thay đổi giá trị props thì tạo variable mới, việc thay đổi hoặc change value của props rất dễ gây confuse cho việc sử dụng sau này, cũng như tiềm ẩn nhiều bug out of control.

3. Mutating property arrays

Trong danh sát Vuejs Anti Pattern được liệt kê ở bài viết này, mutating là pattern không được nhiều người để ý tới. Hoặc sau khi có bug ẩn mới phát hiện và chú ý tới. Pattern này cũng liên quan tới props, tuy nhiên cái cần để tâm là liên quan tới arrays

An important consideration to make when passing down arrays and objects as properties within JavaScript is the fact that they are passed by reference

Một điểm quan trọng khi pass props có kiểu dữ liệu array hoặc object thì kiểu gửi này là kiểu gửi tham chiếu (reference)

Chính vì kiểu gửi tham chiếu nên khi thay đổi data ở component con rất có thể sẽ ảnh hưởng tới props truyền vào ở component cha.

BAD

<template>
  <div>
    <h1>Parent Component</h1>
    <ul>
      <li v-for="friend in friendList" :key="friend.id">{{friend.name}}</li>
    </ul>

    <Person :friendList="friendList" />
  </div>
</template>

<script>
import Person from './components/Person';

export default {
  data() {
    return {
      friendList: [{ id: 1, name: 'John Doe' }]
    }
  },
  components: {
    Person
  }
}
</script>

Ở component con, nếu ta thay đổi value của array truyền vào, sẽ ảnh hưởng trực tiếp tới value ở component cha

<template>
  <div>
    <h1>Child Component</h1>
    <ul>
      <li v-for="friend in friendList" :key="friend.id">{{friend.name}}</li>
    </ul>
    <button @click="addFriend">Add Friend</button>
  </div> 
</template>

<script>
export default {
  props: {
    friendList: {
      type: Array,
    }
  },
  methods: {
    addFriend() {
      this.friendList.push({ id: 2, name: 'Sarah Doe' })
    }
  }
}
</script>

Việc thay đổi mất kiểm soát này có thể phát sinh bug, để tránh những vấn đề không đáng có này, ta có thể tạo variable mới có cùng value với props truyền vào

Vuejs Anti pattern
Component con đổi data, thằng cha đổi theo

GOOD

export default {
  props: {
    friendList: {
      type: Array,
    }
  },
  data() {
    return {
      fList: [...this.friendList]
    }
  },
  methods: {
    addFriend() {
      this.fList.push({ id: 2, name: 'Sarah Doe' })
    }
  }
}

4. Using data as an object

Đây là anti pattern cuối trong chuỗi bài Vuejs Anti Pattern. Pattern này nói về cách sử dụng data. Tuyệt đối tránh sử dụng data như là một object

When creating components with Vue, it’s important that the data option is a function that returns a new object holding data, rather than just a plain data object.

Khi tạo component với Vue, điều quan trọng là data option bản thân nó là một function trả về một object mới, không phải là một data object thuần túy

Nếu ta sử dụng data object không phải là một function, tất cả instance của component sẽ dùng chung một data, không tốt.

Mỗi khi data change, tất cả instance của component cũng sẽ thay đổi theo, cái này khá tệ về mặt performance. Để đảm bảo component chỉ quản lý data thuộc về nó, tránh những component khác bị kéo theo. Ta nên sử dụng return

BAD

data: {
 recipeList: [],
 selectedCategory: 'Desserts'
}

GOOD

data () {
 return {
  recipeList: [],
  selectedCategory: 'Desserts'
 }
}

By creating the return statement, it allows each instance created to have its own object rather than a shared one. This then allows the code to be used multiple times without the conflict of shared data.

Bằng cách sử dụng return, việc này cho phép mỗi instance khi được tạo sẽ có data object của riêng nó. Việc này cũng cho phép code được sử dụng nhiều lần mà không gây ra đụng độ do việc chia sẻ data

Component cũng có thể reuse nhiều lần mà không bị đụng độ cũng như tránh việc update data liên tục ở các component khác.

5. Tham khảo thêm về Vuejs Anti Pattern

Thank for your time to read – Have a great day! – Happy coding!

Có gì thắc mắc cứ comment đây nha! - Please feel free to comment here!