TOP 5 React Best Practices về cấu trúc khi làm việc với React

Tại thời điểm này chúng ta chẳng còn có lý do gì để phủ nhận việc React là một trong những Web Frameworks hàng đầu đã tạo nên nhiều ảnh hưởng đến cách lập trình viên xây dựng giao diện cho người dùng. Chính cuộc cách mạng của React đã giúp chúng ta có nhiều điều kiện hơn trong việc tạo ra các component. Điều đặc biệt là các component này vừa có thể sử dụng và vừa có thể tái sử dụng ở nhiều nơi. Đồng thời trang web của bạn có được những giao diện nhất quán, đồng bộ.

Nhưng, React chỉ thực hiện các công việc ở tầng view trong của mỗi ứng dụng. Do đó, chúng ta không cần tuân theo cấu trúc cụ thể nào, khác với MVC và MVVM. Vì vậy, chúng ta sẽ gặp khó khăn trong việc giữ cho code được mạch lạc khi Project của chúng ta ngày càng lớn.

Tại 9elements với sản phẩm hàng đầu là PhotoEditorSDK – một trong những ứng dụng React quy mô lớn. Chính trong tổ chức ứng dụng React lớn này tác giả cùng những cộng sự đã cung cấp một số React Best Practices cho chúng ta.

Top 5 React Best Practices cho React Developers

1. Cấu trúc thư mục dự án

Như chúng ta thấy thì code dùng để tạo style và code cho những component không cùng nằm chung trong một file. Gần như mọi style đều được đưa vào một file CSS dùng chung chia sẻ trong Project. Component thì lại được tách ra khỏi file style của chính nó. Dưới đây là một ví dụ FiterSlider ở trong component, còn style lại nằm trong file photo-editor-sdk.scss và được đưa vào thư một styles.

react code 1

Sau vài lần refactor, chúng ta nhận thấy rằng cách làm trên không hiệu quả cho các dự án lớn hơn. Trong thời gian tới, những component của chúng ta cần được đưa vào chia sẻ trong các module của dự án, hoặc các dự án có liên quan. Chính điều này khiến nhà sáng lập chuyển qua component làm chủ chốt.

react code 2

Ý tưởng ở đây là các bạn cần tạo một folder sau đó đưa tất cả các đoạn code, style ở trong một component (Như: CSS, test, JavaScript,…) vào folder đó. Với việc làm như này các bạn có thể dễ dàng tách code thành một npm module hoặc trong nhiều trường hợp các bạn cần dùng gấp các bạn có thể share nhanh folder này cho các dự án nhỏ hơn.

Import các component

Một điểm yếu của cách làm là chúng ta cần import đầy đủ và hợp lệ cho mỗi component, như sau:

react code 3

Nhưng một trên thực tế ai cũng ưu dùng kiểu này hơn

react code 4

Để giải quyết vấn đề này chúng ta có thể làm mới tên file chính của component thành một cách đơn giản thành index.js:

react code 5

Nhưng lý do khiến nhiều người không sử dụng đến cách làm này là vì khi chúng ta debug các React Component trên Chrome mà có lỗi xảy ra, Debugger sẽ gửi lại cho bạn một loạt các file có tên index.js

Một cách làm khác có thể khắc phục được điểm yếu trên đó là dùng directory-named-webpack-plugin. Plugin dạng này tạo ra quy luật cho webpack resolver. Quy luật này sẽ giúp webpack nhanh chóng tìm chính xác một file JavaScript hoặc JSX có tên khớp với tên thư mục mà nó đang import. Tuy nhiên với cách làm này các bạn sẽ gặp phải một rắc rối đó là thư mục vendor sẽ đi liền với webpack. Đây chính là vấn đề khiến cho người sử dụng Rollup để bundle các library. Hơn nữa việc update các webpack phiên bản mới không phải là một điều dễ dàng.

Một giải pháp hữu hiệu được đưa ra trong trường hợp này là sử dụng cơ chế resolve tiêu chuẩn của Node.js. Với giải pháp này chúng ta sẽ giảm tối đa được rủi ro trong tương lai. Công việc của chúng ta thật đơn giản chỉ cần tạo một file package.json vào trong cấu trúc thư mục.

react code 6

Ngay trong file package.json, chúng ta sử dụng thuộc tính main để set đầu vào cho component:

react code 7

Sau các việc setup trên chúng ta có thể import component dưới đây:

react code 8

2. CSS trong Javascript

Vấn đề mà chúng ta gặp khó khăn nhất đó chính là tạo các style đặc biệt là các themme. Như chúng ta đề cập ở trên, chúng ta sử dụng một file CSS (SCSS) để chứa tất cả những class css. Và cách làm để giảm hiện tượng trùng lặp là sử dụng các prefix toàn cục và tuân theo BEM convention để đặt tên class. Tuy nhiên khi các ứng dụng ngày càng được cải tiến, cách làm này sẽ không còn phù hợp và cần có những cách làm thay thế. Và một ý tưởng được đưa ra đó là sử dụng CSS module, nhưng mặt trái đó là nó có thể gây ra một số vấn đề liên quan đến hiệu năng. Chính cách tách CSS bằng Extract Text plugin của webpack đã gây ra hậu quả là việc test sau này trở nên khó khăn.

Một số giải pháp tiếp đó là CSS-in-JS được coi là mới và được mọi người xem xét:

  • Style Components: được cộng đồng người dùng lựa chọn nhiều nhất hiện nay
  • EmotionJS: được coi là một đối thủ top đầu của Style Components
  • Glamorous: một trong số cách làm phổ biến khác

Nhưng việc lựa chọn cách làm nào là phụ thuộc vào dự án mà chúng ta đang làm:

  1. Nếu bạn cần một thư viện để xuất fiel CSS đã được compile dành cho môi trường production thì EmotionJS là một lựa chọn hợp lý.
  2. Nếu tạo themme là một rắc rối với bạn, bạn nên chọn Styled Components và Glamorous để giảm thiếu rắc rối.
  3. Hay đơn giản bạn cần chúng hoạt động hiệu quả trên server, có lẽ các bạn nên chọn những phiên bản gần đây của những thư viện kể trên.

Gần như với những project, Styled Components là một lựa chọn hợp lý. Bởi lẽ với Styled Components chúng hoạt động mạnh mẽ và có cộng đồng lớn phía sau. Có thể nói thư viện này rất đồ sộ, đặc biệt với việc tạo các themme phức tạp chúng ta không còn gặp những vấn đề khó khăn nữa.

Cố gắng xây dựng các React Component chỉ đảm nhiệm một vai trò duy nhất

Trong lúc các bạn xây dựng những Component UI có tình trừu tượng cao các bạn sẽ gặp phải vấn đề khó khăn để tách và lựa ra những tiêu chí. Ở một thời điểm nhất định nào đó Component của bạn sẽ yêu cầu sự logic từ model, lúc này mọi thứ bạn làm sẽ gặp phải rắc rối. Tiếp đó là một số các phương pháp để DRY các Component được giới thiệu. Có thể những kỹ thuật này sẽ gây ra sự trùng lặp về tính năng hoặc lựa chọn kỹ thuật. Nhưng những kiến trúc mà bạn tạo ra lại phụ thuộc nhiều hơn vào sở thích. Dù sao chúng ta cũng hãy tham khảo những trường hợp sử dụng trước:

  • Với trường hợp cần một cơ chế làm việc với những Component có nội dung không giống nhau đối với người sử dụng đăng nhập/ hoặc chưa đăng nhập.
  • Với trường hợp cần render một table gồm nhiều phần tử <tbody> các bạn có thể collaspe.
  • Để hiển thị những Component khác nhau có sự phụ thuộc vào state. Tiếp đó là những giải pháp cho những vấn đề được miêu tả ở trên.

3. Higher-order Component (HOC)

Trong nhiều trường hợp bạn phải chắc chắn rằng một React Component chỉ xuất hiện khi mà người dùng đã có những lần đăng nhập trước đó vào ứng dụng của bạn. Bạn có thể sử dụng hàm render để liên tục kiểm tra. Công việc này sẽ được làm cho đến khi bạn nhận ra rằng bạn code của bạn đang được lặp lại. Khi bạn thực hiện công việc DRY code sớm muộn bạn cũng sẽ thấy được các higher-order-component có thể giúp bạn tách và trừu tượng một vài tiêu chí của Component. higher-order-component được ví như một dạng của decorator pattern. Cách hoạt độn của một higher-order-component (HOC) rất đơn giản, chúng chỉ nhận một React component làm tham số, sau đó sẽ trả về một React component khác nó. Dưới đây là minh họa:

Việc nhận vào một component (WrappedComponent) được đảm nhận bởi hàm requiresAuth. Những component sẽ được trang trí theo mong muốn người dùng. Trong hàm, class AuthenticatedComponent sẽ render ra các component đó và thêm vào đó những tính năng hợp lý để kiểm tra sự tồn tại của người dùng trong ứng dụng. Nếu không có sẽ được redirect chuyển qua trang đăng nhập. Kết lại, component sẽ liên kết tới store của Redux và return về. Có thể ở ví dụ này Redux là hữu hiệu, nhưng không phải trong tất cả các project chúng ta đều cần đến nó.

4. Truyền hàm render vào component với children prop

Để tạo ra một Row của Table với collaspe là một điều không hề đơn giản. Câu hỏi mà bạn sẽ gặp phải đó là render nút collaspe sao cho hợp lý? Làm sao để hiển thị children khi table không collaspe? Tuy nhiên với JSX 2.0 công việc dần được đơn giản hóa hơn chút ít. Giờ đây các bạn đã có thể return cả một mảng thay vì duy nhất một html tag. Các bạn hãy theo dõi ví dụ dưới đây để hiểu thêm về pattern Function as children. Hãy cũng theo dõi:

Tiếp là table body có thể collapse

Công việc của bạn thật đơn giản là chuyền một function qua children, function được gọi trong hàm render của các component. Kỹ thuật này còn có một tên gọi khác là render callback.

5. Render props

Tác giả của thuật ngữ “Render props” là Michael Jackson. Với gợi ý là các pattern higher-order component có thể sẽ được thay thế bởi những component cơ bản với một “Render prop”. Ban đầu Michael Jackson định hướng là truyền react component vào trong hàm, các bạn có thể gọi dưới dạng thuộc tính hoặc gọi hàm ở chính hàm render.

Dưới đây là đoạn code minh họa:

Một thuộc tính là render như các bạn thấy ở trên, đây là một function được gọi trong quá trình mà các bạn render. Hàm mà các bạn gọi trong nó lấy về state hoàn chỉnh làm tham số của nó được trả về JSX. Hãy theo dõi công năng của nó dưới đây:

Nhìn đoạn code trên những tham số data và isLoading được destruct từ object state hay sử dụng để lấy response về từ JSX. Ở trường hợp này, khi promise chưa được fulfilled, dòng “Loading” sẽ hiển thị. Phần nào của state được truyền vào cho “render prop” sẽ tùy thuộc vào quyết định mà bạn đưa ra cho giao diện của bạn. Bởi lẽ render prop pattern là sự tổng quát của pattern Fuction as children. Do vậy không có quá nhiều thứ ngăn cản việc bạn có quá nhiều render props trong một component.