Cách tư duy trong React

Theo ý kiến của chúng tôi thì React là một trong những cách tốt nhất để xây dựng một web app nhanh và lớn với Javascript. Nó đã được mở rộng rất tốt ở Facebook và instagram.

Một trong những phần tuyệt vời của React là cách nó khiến bạn nghĩ về các apps như là bạn build chúng. Trong tài liệu lần này, chúng tôi sẽ đưa bạn đi qua cách suy nghĩ về xây dựng một bảng dữ liệu tìm kiếm sản phẩm sử dụng React.

Bắt đầu với Mock

Hãy tưởng tượng rằng chúng tôi đã có JSON API từ người thiết kế. Mock sẽ trông như thế này:

alt text

Và JSON API trả về dữ liệu trông như thế này:

  {category: "Sporting Goods", price: "$49.99", stocked: true, name: "Football"},
  {category: "Sporting Goods", price: "$9.99", stocked: true, name: "Baseball"},
  {category: "Sporting Goods", price: "$29.99", stocked: false, name: "Basketball"},
  {category: "Electronics", price: "$99.99", stocked: true, name: "iPod Touch"},
  {category: "Electronics", price: "$399.99", stocked: false, name: "iPhone 5"},
  {category: "Electronics", price: "$199.99", stocked: true, name: "Nexus 7"}
];

Bước 1: Phá vỡ UI thành các component theo thứ tự phân cấp

Đầu tiên bạn sẽ muốn vẽ các khung bao quanh mỗi component(và các component con) trong mock và đặt tên cho chúng. Nếu bạn làm việc với người thiết kế thì họ có thể đã hoàn thành nó, nên là hãy nói chuyện với họ. Tên của các lớp Photoshop có thể trở thành tên của các React component của bạn.
Nhưng làm thế nào bạn biết cái gì nên được là component của nó? Sử dụng các kĩ thuật tương tự để chia nhỏ nếu bạn tạo ra một function hoặc object mới. Một trong những kĩ thuật đó là Quy tắc đơn nhiệm, tức là mỗi component nên chỉ làm một nhiệm vụ. Nếu nó đã dừng phát triển thì nên chia nhỏ nó thành các component con.
Nếu bạn thường xuyên hiển thị kiểu dữ liệu JSON tới user, bạn sẽ khám phá ra rằng nếu mô hình được thực hiện đúng, thì UI( và do đó là cấu trúc component) sẽ được map tốt. Đó là bởi vì UI và mô hình dữ liệu thường có xu hướng tuân thủ cùng loại thông tin kiến trúc. Tách rời UI vào trong các component,nơi mỗi component được nối với một mảnh của mô hình dữ liệu.

alt text

Nhìn vào hình ở phía trên ta sẽ thấy có năm component, chúng tôi sẽ in nghiêng dữ liệu của mỗi component đại diện.

1. FilterableProductTable(orange): bao gồm toàn bộ ví dụ trên
2. SearchBar (blue): nhận tất cả dữ liệu nhập vào
3. ProductTable (green): hiển thị và lọc kết quả dựa vào dữ liệu từ người dùng nhập vào
4. ProductCategoryRow (turquoise): hiển thị tiêu đề cho mỗi thể loại
5. ProductRow (red): hiển thị mỗi hàng cho mỗi sản phẩm

Nếu bạn nhìn vào ProdecutTable, bạn sẽ thấy rằng tiêu đề của bảng (bao gồm name và price) là các thành phần riêng. Đây là một vấn đề được ưu tiên, đã có một cuộc tranh luận được đưa ra. Ví dụ, chúng ta để nó như một phần của ProductTable bởi vì nó là một phần
của tập dữ liệu mà ProductTable chịu trách nhiệm. Tuy nhiên, nếu tiêu đề trở nên phức tạp (ví dụ chúng ta đã thêm chi phí để sắp xếp) nó chắc chắn sẽ phù hợp để sở hữu component ProductTableHeader.
Nếu chúng ta đã xác định được các components ở trong mock, hãy sắp xếp chúng thành một hệ thống phân cấp, Component xuất hiện bên trong một component khác trong mock nên được xuất hiện như một component con trong hệ thống phân cấp:

  • FilterableProductTable
    • SearchBar
    • ProductTable
      • ProductCategoryRow
      • ProductRow

Bước 2: Xây dựng một phiên bản tĩnh trong React

Xem code của bước 2 trên CodePen.

Nếu bây giờ bạn có một hệ thống phân cấp component, bây giờ là thời điểm để triển khai vào app. Cách dễ nhất là xây dựng một phiên bản lấy dữ liệu và kết xuất nó ra UI nhưng không có sự tương tác. Nó khá hữu hiệu để tách các tiến trình này bởi vì xây dựng một phiên bản tĩnh cần viết nhiều và không có sự tư duy, ngược lại khi thêm tương tác cần tư duy nhiều nhưng viết khá ít. Chúng ta sẽ làm rõ vấn đề này.
Để xây dựng một phiên bản tĩnh cho việc kết xuất dữ liệu, bạn sẽ muốn xây dựng các component mà có thể tái sử dụng và sử dụng props để truyền dữ liệu. prop là một cách để truyền dữ liệu từ component cha tới component con. Nếu bạn đã quen với khái niệm của state, đừng chỉ sử dụng state để xây dựng một phiên bản tĩnh. State chỉ dành riêng cho tương tác, tức là dữ liệu thay đổi theo thời gian. Và đây là một phiên bản tĩnh, nên bạn không cần phải dùng nó. Bạn có thể xây dựng từ trên xuống hoặc từ dưới lên. Nghĩa là bạn có thể bắt đầu xây dựng component cao hơn trong cấu trúc phân cấp ( tức là bắt đầu với FilterableProductTable), hoặc với một component thấp cấp hơn(ProductRow). Trong các ví dụ đơn giản, sẽ dễ hơn để xây dựng từ trên xuống nhưng trong các dự án lớn hơn, dễ dàng để xây dựng từ dưới lên và viết test cho các component.
Cuối bước này, bạn sẽ có một thư viện component tái sử dụng cho việc kết xuất dữ liệu. Component sẽ chỉ có hàm render() vì đây là phiên bản ứng dụng tĩnh. Component phía trên cấu trúc phân cấp (FilterableProductTable) sẽ lấy dữ liệu như một props. Nếu bạn Nếu bạn thay đổi mô hình dữ liệu cơ bản và gọi ReactDOM.render() lần nữa, UI sẽ được cập nhật. Bạn có thể thấy UI thay đổi như thế nào và ở đâu thay đổi. Dòng dữ liệu một chiều của React (còn được gọi là liên kết một chiều) giữ mọi thứ mô đun hóa và nhanh chóng.
Chuyển tới tài liệu này nếu bạn cần giúp đỡ để thực hiện bước này.

So sánh : Props vs State

Trong React có hai kiểu ‘mô hình’ dữ liệu: props và state. Hiểu được sự khác biệt giữa hai kiểu này rất quan trọng. Đọc tài liệu chính thức của React nếu bạn không chắc chắn hiểu được sữ khác biệt giữa chúng. Đọc thêm FAQ: What is the difference between state and props?

Bước 3: Xác định miêu tả tối thiểu (nhưng đầy đủ) của trạng thái UI

Để làm giao diện người dùng tương tác, bạn cần có khả năng kích hoạt những thay đổi nằm dưới mô hình dữ liệu. React thực hiện nó với state.
Để xây dựng ứng dụng một cách đúng đắn, đầu tiên bạn cần suy nghĩ về một tập hợp tối thiểu của trạng thái có thể biến đổi mà ứng dụng cần. Từ khóa là DRY: Don’t Repeat Yourself . Tìm ra miêu tả tối thiểu tuyệt đối của trạng thái mà ứng dụng cần và tính toán mọi thứ khác mà bạn cần theo yêu cầu. Ví dụ, nếu bạn xây dựng một danh sách những việc cần làm, giữ một mảng các mục cần làm ở xung quanh, không giữ các biến trạng thái riêng để đếm. Thay vào đó, khi bạn muốn kết xuất danh sách việc cần làm, lấy độ dài của mảng danh sách đó.
Tư duy về tất cả các mảnh dữ liệu trong ví dụ đầu tiên. Chúng ta có:

  • Mảng ban đầu của các sản phẩm
  • Từ khóa tìm kiếm mà người dùng nhập vào
  • Giá trị của ô checkbox
  • Danh sách lọc của các sản phẩm
    Hãy đi qua từng cái và tìm ra các trạng thái. Có ba câu hỏi về các mảnh dữ liệu:
  1. Có phải nó được truyền vào từ component cha qua props? Nếu vậy, nó có lẽ không phải là state.
  2. Có phải nó không thay đổi theo thời gian? Nếu vậy, có lẽ nó không phải là state
  3. Bạn có thể tính toán dựa trên bất kì state hoặc props nào khác không? Nếu vậy, có lẽ nó không phải là state.
    Danh sách các sản phẩm ban đầu được truyền vào như một props, nên nó không phải là state. Câu tìm kiếm và checkbox dường như trở thành state khi chứng thay đổi theo thời gian và không thể tính toán từ bất cứ thứ gì. Và cuối cùng, danh sách tìm kiếm các sản phẩm không phải là state bởi vì chúng có thể được tính toán bằng cách kết hợp với danh sách sản phẩm ban đầu với từ khóa tìm kiếm và giá trị của ô checkbox.
    Nên cuối cùng, state là:
  • Câu tìm kiếm mà người dùng đã nhập
  • Giá trị của ô checkbox

Bước 4: Xác định nơi mà state tồn tại

Xem bước 4: Thinking In React: Step 4 trên CodePen.
Qua các bước trên chúng ta đã xác định tập tối thiểu của các trạng thái Tiếp theo, chúng ta cần xác định các component có thể thay đổi, hoặc sở hữu state.
Hãy nhớ rằng: React là tất cả về luồng dữ liệu xuống các component ở phía sau. Nó có thể không chắc chắn ngay rằng component nào sở hữu state nào. Nó là một trong những phần thách thức phổ biến cho người mới bắt đầu, nên qua những bước sau chúng ta sẽ khám phá nó:
Cho mỗi mảnh của trạng thái trong ứng dụng :

  • Xác định mỗi component kết xuất một thứ gì đó dựa trên state.
  • Tìm component sở hữu chung(một component đơn ở phía trên tất cả các component mà cần state trong hệ thống phân cấp).
  • Các component sở hữu chung và các component khác cao hơn trong hệ thống phân cấp nên sở hữu state.
  • Nếu bạn không thể tìm thấy một component mà nó sở hữu state một cách hợp lí, hãy tạo một component duy nhất để giữ các state, và thêm nó vào một nơi nào đó trong hệ thống phân cấp mà được sở hữu chung bởi một component.
    Hãy xem lại chiến lược này trong ứng dụng:
  • ProductTable cần lọc danh sách sản phẩm dựa trên state và SeachBar cần hiển thị câu tìm kiếm và kiểm tra trạng thái.
  • component sở hữu chung là FilterableProductTable.
  • Về mặt khái niệm thì hợp lí để lọc các câu tìm kiếm và các giá trị đã check của ô checkbox tồn tại trong FilterableProductTable.
    Chúng ta đã quyết định rằng state tồn tại trong FilterableProductTable. Đầu tiên, thêm một ví dụ thuộc tính this.state = {filterText: '', inStockOnly: false} trong FilterableProductTable’s constructor để phản ánh trạng thái ban đầu của ứng dụng. Sau đó truyền filterTextinStockOnly vào ProductTableSearchBar như props. Cuối cùng sử dụng những props đó để lọc các hàng trong ProductTable và thiết lập giá trị của các trường trong form trong SearchBar.
    Bạn sẽ bắt đầu thấy ứng dụng hoạt động như thế nào: Thiết lập filterTextball và tải lại ứng dụng. Bạn sẽ thấy bảng dữ liệu được cập nhật lại một cách đúng đắn

Bước 5: Thêm luồng data ngược lại.

Xem code của bước 5 Thinking In React: Step 5 trên CodePen.
Cho đến nay, chúng ta đã xây dựng ứng dụng mà kết xuất một cách đúng đắn như một function của propsstate xuống hệ thống phân cấp.
React làm cho luồng dữ liệu này rõ ràng để giúp bạn hiểu ứng dụng làm việc như thế nào, nhưng nó đòi hỏi phải gõ nhiều hơn một chút so với ràng buộc dữ liệu hai chiều truyền thống. Nếu bạn thử nhập hoặc tíc vào ô trong phiên bản hiện tại của ví dụ, bạn sẽ thấy React bỏ qua câu nhập vào. Đó là cố ý, như chúng ta đặt thuộc tính value của input luôn luôn bằng state truyền vào từ FilterableProductTable.
Hãy suy nghĩ về điều chúng ta muốn xảy ra. Chúng ta muốn chắc chắn rằng bất cứ khi nào người dùng thay đổi form, chúng ta sẽ cập nhật state để phản ánh lại giá trị mà người dùng nhập vào. Từ khi component chỉ cập nhật state mà chúng sở hữu, FilterableProductTable sẽ truyền các callback tới SearchBar mà sẽ fire bất cứ khi nào state được cập nhật. Chúng ta có thể sử dụng sự kiện onChange trên ô input để xác thông báo nó. Các callback được truyền bởi FilterableProductTable sẽ được gọi bởi setState và ứng dụng sẽ được cập nhật

Và đó là

Hi vọng nó sẽ cho bạn một ý tưởng về việc xây dựng component và ứng dụng với React như thế nào. Trong khi nó có thể phải nhập nhiều hơn một chút so với bạn sử dụng, hãy nhớ rằng các đoạn code được đọc nhiều hơn nó được viết, và nó ít khó hơn để đọc code rõ ràng theo mô đun hóa. Nếu bạn xây dựng một thư viện lớn các component, bạn sẽ đánh giá tính rõ ràng và mô đun hóa này, và với các đoạn code tái sử dung, số dòng code của bạn sẽ ít hơn.