Tối ưu hóa hiệu năng ứng dụng React nâng cao.

Tram Ho

React rất là nhanh. Mình thực sự thấy nó rất nhanh. Đó là điều làm cho React thực sự tuyệt vời.

Nhưng nếu bạn muốn tối ưu hóa ứng dụng của bạn thì có một số cách bạn có thể làm.

Hôm nay chúng ta sẽ thấy 2 công nghệ hữu dụng nhất được React cung cấp sẽ giải quyết những vấn đề về hiệu năng như thế nào.

1. Bắt đầu với một ví dụ đơn giản.

Lấy một ví dụ đơn giản, chúng ta có một component Display hiển thị một dòng văn bản.

Component này là con của component Controller, trong đó Controller còn chứa một nút có tác dụng làm tăng giá trị biến count trong state khi được click vào.

Chúng ta thêm console.log(...) vào để phát hiện component Display của chúng ta có bị render lại hay không.

Bây giờ, khi chúng ta click vào button bên trong Controller và mở console.

Mặc dù chúng ta không hề tác động gì tới component Display nhưng mà nó luôn bị render lại mỗi khi chúng ta click vào button.

Điều này không hề ổn một chút nào. Điều gì sẽ xảy ra nếu chúng ta sử dụng component Display này ở trên toàn bộ project?

Hiệu năng sẽ hoàn toàn bị phá vỡ.

2. Memoization là gì ?

Memoization là một kĩ thuật quen thuộc được sử dụng ở rất nhiều nơi. Nó cũng không có gì ngoài bộ nhớ đệm (caching).

Theo Wikipedia nó được định nghĩa như sau :

In computing, memoization or memoisation is an optimization technique used primarily to speed up computer programs by storing the results of expensive function calls and returning the cached result when the same inputs occur again.

Như vậy, Nếu memoization là một kĩ thuật giúp cải thiện hiệu năng cho các hàm (function), chúng ta có thể ứng dụng nó cho functional component hay không ?

Yes, rất may chúng ta có thể làm nó. React cung cấp cho chúng ta một tính năng được gọi là React.memo()

Bây giờ, chúng ta hãy xem cách để giải quyết vấn đề trên.

3. Sử dụng React.memo() để chặn render lại (re-render).

React.memo() nhận vào 2 tham số :

  • Đầu tiên là hàm mà chúng ta muốn ghi nhớ (memorize).
  • Thứ 2 là hàm có chức năng giống như shouldComponentUpdate() (optional). Chúng ta sẽ gọi nó sau,

Bây giờ, nhìn xem điều gì sẽ xảy ra nếu chúng ta viết lại component Display như sau …

Thật tuyệt vời, component của chúng ta đã không bị render lại mỗi khi click vào button.

4. Hãy tiến thêm một bước nữa.

Okey, bây giờ chúng ta đã có một component tối ưu. Nhưng vấn đề là component này thật ngu ngốc, nó chỉ hiển thị một dòng text. chả có tác dụng gì cả. Tôi muốn nội dung của Display phụ thuộc vào một vài props truyền vào nó.

Bây giờ sẽ viết lại component Display cho nó hiển thị một danh sách tên người.

Mỗi khi click vào button sẽ thêm một cái tên mới vào state.

Chúng ta sẽ nhìn thấy another name được thêm vào danh sách tên mỗi lần click vào button Add Name.

Nhưng không có gì xảy ra cả. Tại sao vậy ? Chúng ta sẽ giải đáp thắc mắc này trong phần tiếp theo.

5. Mutable vs Immutable.

Để giải quyết vấn đề này, chúng ta phải thực sự hiểu về Immutable ( tính bất biến )

Ở dòng newNames = names, chúng ta nghĩ rằng gắn names cho biến mới newNames nhưng thực sự arrays trong Javascript không làm việc như vậy.

Khi thực hiện dòng lệnh trên, nó sẽ gán tham chiếu của mảng names cho newNames. Nên kết quả là nội dung của mảng names thay đổi nhưng tham chiếu không hề thay đổi.

Và tất nhiên chúng ta đều biết React chỉ re-render lại khi state thay đổi nên việc chạy hàm addName() kia hoàn toàn không có tác dụng.

Chúng ta giải quyết vấn đề này bằng các viết lại hàm addName() như sau …

Toán tử ... (spread operator) trả về một mảng mới và gán cho newNames.

Bây giờ nếu chúng ta click vào button, chúng ta có thể thấy component đã được render lại.

6. Khi React.memo không được, hãy sử dụng useCallback() để giải quyết.

Vòa một ví dụ khác. Chúng ta tạo một component tương tự ví dụ trước, sẽ thêm một cái tên mới mỗi khi click vào button.

Và chúng ta có một component khác để xóa danh sách tên trên.

Bây giờ, chúng ta click vào button Add Name. Component ClearButton đã bị render lại, điều này là không cần thiết.

Để giải quyết vấn đề này chúng ta có thể sử dụng một hook tên là useCallback(). Cái hook useCallback() này giúp chúng ta ngăn chặn việc tính toán lại (re-computing) clearNames. Nó được cung cấp bởi React và có thể import như sau …

Và chúng ta có thể viết lại hàm clearNames như sau …

Yeee, vấn đề của chúng ta không còn nữa !

Tổng kết lại thì trên đây là một số các bạn có thể sử dụng để cải thiện ứng dụng React của mình. Nhưng những điều tốt đẹp thì thường đi cùng cạm bẫy. Nên hãy cố gắng sử dụng khôn ngoan để tránh ăn bug nhé các bạn.

Còn các bạn làm gì để tối ưu hiệu năng ứng dụng React, hãy comment cho mình và mọi người tham khảo nhé! Happy Coding!

Tìm hiểu thêm :

Chia sẻ bài viết ngay

Nguồn bài viết : Viblo