07/09/2018, 16:59

Những đặc điểm quyết định sự thành công khi xây dựng một React Component

Một trong những feature hay nhất của React, một trong vạn lý do mà có rất nhiều người yêu thích khi sử dụng React, đó là vì nó cho bạn khả năng tự do lựa chọn các cách tiếp cận khác nhau đối với từng vấn đề. Là một thư viện cốt yếu sử dụng cho việc thiết kế và xây dựng View, React cung cấp cho bạn ...

Một trong những feature hay nhất của React, một trong vạn lý do mà có rất nhiều người yêu thích khi sử dụng React, đó là vì nó cho bạn khả năng tự do lựa chọn các cách tiếp cận khác nhau đối với từng vấn đề. Là một thư viện cốt yếu sử dụng cho việc thiết kế và xây dựng View, React cung cấp cho bạn vô vàn những phương án khác nhau trong việc bạn gửi các HTTP request như thế nào, bạn thiết kế, trang trí các component của bạn như thế nào, hay việc bạn sử dụng convention nào để đặt tên và rất nhiều vấn đề khác. React để cho bạn toàn quyền quyết định những việc đó. Theo kinh nghiệm của một số người thì đây là điều rất tốt, và thường thì một số bộ convention hoạt động tốt ở một trong các ứng dụng của bạn xây dựng chưa chắc đã là hợp lý đối với các ứng dụng khác, việc sở hữu sự linh hoạt đó là điều ta cần phải đánh giá, xem xét lại. Qua một vài năm ngồi viết, xây dựng các React Component, mình đã tìm hiểu và thống kê được một vài quy chuẩn mà mình thường xuyên làm theo khi xây dựng các component và dưới đây mình muốn chia sẻ những quy định mình tự đúc kết được đó. Và mình rất vui nếu được nghe những ý kiến khác phản đối hay góp ý hay thêm các quy chuẩn cho bài viết bởi tất cả dưới đây đều là các tham khảo cá nhân mình thu thập được.

Nếu phải lựa chọn ra một quy định hay nhất, chính xác nhất trong danh sách dưới đây thì chắc chắn cá nhân mình sẽ chọn quy định này. Cách tiếp cận mà mình hướng tới ở đây đó là việc bạn có thể có thật nhiều, rất nhiều các React Component mà bạn thấy cần thiết và đừng bao giờ cảm thấy sợ việc mình đang sử dụng hay xây dựng quá nhiều component. Các component được sinh ra là để kết hợp vào với nhau và bạn nên kết hợp các component với nhau khi thấy nó hợp lý và tránh việc để một component phải thực hiện quá nhiều chức năng.

Một dấu hiệu để nhận biết bạn có thực hiện đúng quy định này không đó là việc kiểm tra xem hàm render của bạn có dài quá mức không. Đó là một biểu hiện của việc một component đang làm quá nhiều việc đáng lẽ ra có thể tách và giao phó cho một component khác. Một biểu hiện đơn giản khác đó là việc component của bạn đang sở hữu quá nhiều state hoặc props. Nếu bạn đang phải lưu trữ một lượng lớn dữ liệu trong một component, hoặc phải nhận vào đến 10 props để có thể đảm bảo chắc chắn rằng component đó đã được configure đúng, thì rất có thể bạn nên thay vào đó sử dụng nhiều các component nhận vào ít props hơn.

Lấy ví dụ về một component được dùng lấy về dữ liệu của các user từ một API, liệt kê các user đó vào một danh sách và cho phép bạn click để xem thông tin của user được chọn. Ta sẽ có khoảng 3 hàm riêng biệt để tạo ra component này. Đầu tiên là xử lý logic HTTP trong hàm componentDidMount để lấy về thông tin các user:

    componentDidMount() {
        fetchUsersFromMyApi()
            .then(users => this.setState({ users }))
            .catch(error => this.handleErrors(error));
    }

Sau đó bạn có đoạn code để liệt kê danh sách các user ra, có thể là trực tiếp trong hàm render hoặc trong một hàm khác mà bạn sẽ gọi lại trong hàm render:

renderUsers() {
  return (
    <ul>
      {this.state.users.map(user =>
         <li key={user.id} onClick={() => this.viewUser(user.id)}>{user.name}</li>
      )}
    </ul>
  )
}

Và bạn cần có đoạn logic để set user được active vào trong state:

viewUser(userId) {
  this.setState({ activeUser: this.state.users[userId] })
}

Cuối cùng là đoạn logic trong hàm render:

render() {
  return (
    <div>
      { this.renderUsers() }
      { this.state.activeUser && <div>output user things here</div>}
    </div>
  )
}

Ta có thể dễ dàng tuy code ngắn nhưng component này đang phải làm quá nhiều công việc bên trong nó. Hãy tưởng tượng nếu bạn phải viế t test cho component này, bạn sẽ phải mock ra một request HTTP, kiểm tra xem nó có xử lý đúng trong trường hợp thành công, trường hợp có lỗi hay không, kiểm tra xem nó có liệt kê ra đúng danh sách các user và kiểm tra xem nó có show ra đúng thông tin user được chọn khi bạn click vào từng user hay không. Có quá nhiều test case phải viết ra chỉ cho một component. Thay vào đó, hãy thử tưởng tượng nếu ta có một bộ các component có thể kết hợp lại với nhau.

Component đầu tiên được gọi là UsersContainer, có thể sẽ phụ trách việc lấy về dữ liệu của các user từ API và sau đó truyền xuống cho component UserList, và cùng lúc đó có thể sẽ render ra component User.

Bằng cách làm như trên, bạn sẽ có được một cây các component, với mỗi component chỉ có duy nhất một công việc và sau đó chuyển các phần việc còn lại xuống cho các component con:

  • UserContainer lấy dữ liệu, hiển thị loading spinner hoặc lỗi, truyền dữ liệu xuống.
  • UserList liệt kê danh sách các user, giao nhiệm vụ render từng user ra cho component User. Theo dõi xem user nào được active.
  • User có thể render ra từng user riêng biệt và xử
0