Tối ưu React Update

Sự dễ dùng của React khi muốn cập nhật lại view chỉ bằng việc setState đã vô tình tạo ra một vấn đề nghiêm trọng về hiệu năng. Hầu hết mọi người khi mới bắt đầu phát triển ứng dụng với React sẽ không thể kiểm soát được số lần update (re-render) của một React Component do không tối ưu React Update, từ đó dễ khiến ứng dụng bị chậm.

Trong rất nhiều trường hợp, việc một Component render nhiều lần sẽ không có quá nhiều ảnh hưởng tới những ứng dụng nhỏ. Nhưng đối với những ứng dụng có cấu trúc lớn dẫn đến tình trạng các Component thường xuyên sẽ phải lồng vào trong nhau (nested), khi này việc render nếu không được xử lý khéo léo sẽ dẫn tới việc hiệu năng bị ảnh hưởng.

Câu hỏi bạn thường không trả lời

Thực ra, mỗi React Component khi được tạo ra luôn có một câu hỏi: Tôi có nên update không? Nhưng không nhiều người chịu trả lời. Mặc định các Component khi hỏi mà không được đáp lại thì sẽ mặc nhiên coi là đồng ý.

shouldComponentUpdate(nextProps, nextState) {
    return true
}

Theo cách này, cứ mỗi khi setState được gọi là Component update thoải mái. Như mình đã trình bày ở trên, nếu ứng dụng của bạn nhỏ và không cảm thấy giật lag gì thì có thể bỏ qua phần tối ưu này. Nhưng nếu ứng dụng của bạn có dấu hiệu chậm, bạn có thể cân nhắc về việc trả lời câu hỏi bên trên.

shouldComponentUpdate(nextProps, nextState) {
    return nextProps.someProp !== this.props.someProp    
}

Nếu prop someProp thay đổi, nextProps.someProp sẽ khác với this.props.someProp, kết quả bên trên sẽ trả về true, Component được update. Còn nếu không thay đổi, Component sẽ không update

> Đây chỉ là cách tối ưu căn bản nhất, điều mà đáng lẽ ra mỗi lập trình viên React nên làm

Nếu bạn vẫn không muốn trả lời

Như đã nói bên trên, nếu bạn trả lời đầy đủ câu hỏi ở trên với mỗi Component, việc update của React lúc này chắc chắn là đã cải thiện hơn trước rất nhiều. Tất cả những Component giờ đây sẽ chỉ được update khi có thay đổi từ state hoặc prop. Nhưng sự thực là bạn sẽ cảm thấy rất mệt mỏi nếu như cứ phải tối ưu từng Component như vậy. May mắn thay, React gửi bạn một anh bạn trợ lý sẽ tự động trả lời cho bạn. Anh bạn này sẽ tự động so sánh và trả lời cho Component rằng có nên update hay không. Nếu prop, state thay đổi, anh bạn này sẽ nói với Componentupdate, còn nếu không thì sẽ không updatePure Component

Cơ bản thì thay vì bạn phải trả lời câu hỏi bên trên, anh bạn này sẽ trả lời giúp bạn. Tất cả những gì bạn cần phải làm đó là khi viết một React Component, thay vì extends React.Component, bạn sẽ cần phải extends React.PureComponent.

> PureComponent so sánh nông nên nếu props và state của bạn có cấu trúc phức tạp, PureComponent sẽ trả lời sai. Đây cũng không phải là giải pháp triệt để của việc tối ưu update trong React. Tuy nhiên, nó nhanh và dễ cho người mới bắt đầu.

Sự thực về React render

Việc tối ưu React updates thực ra là hạn chế các update không cần thiết theo dạng tree-view update (nested update). Khi Component cha render mà mình không muốn Component con render. React đã nói về shouldComponentUpdate cũng như PureComponent của mình và điều này ít nhiều đã giúp tối ưu được phần nào về quá trình update này. Tuy nhiên, điều React không nói với mình là React Component không thực hiện việc render.

Hay nói cách khác việc bạn đưa lifecycle shouldComponentUpdate chỉ nhằm mục đích nói với React là bạn muốn Component của mình sẽ render ra như thế nào. Việc render nằm ở ReactDOM và thực tế là ReactDOM còn chẳng cần đến state để render. ReactDOM chỉ đơn giản là gọi ra hàm render.

Theo cách đó, bạn hoàn toàn có thể tạo ra một Component thoát ra khỏi tree-view update bằng việc tạo một data source bên ngoài. Khi nào cần update/render thì gọi hàm forceUpdate để vẽ lại.

import React from "react";
let data = 'I am a custom data, not a state anymore'
let instance
setTimeout(() => {
  data = 'I have been changed after quite some time'
  instance.forceUpdate()
}, 3000)
export default class App extends React.Component{
  componentDidMount() {
    instance = this
  }
  shouldComponentUpdate() {
    // this is important
    // you tell Component that you won't use state anymore
    return false
  }
  render() {
    return (
      <div>
        <h1>{data}</h1>
      </div>
    );
  }
}

> Trong hầu hết các trường hợp, bạn không cần đến phương pháp này. Nhưng đây sẽ là cách mà bạn có thể kiểm soát một cách triệt để đối với việc một React Component sẽ được render ra thế nào, qua đó tối ưu React Update.

Tổng kết

Không nhất thiết lúc nào mình cũng cần phải tối ưu update của React. Trong nhiều trường hợp, dù bạn không hề tối ưu thì React cũng đã update đủ nhanh và không ảnh hưởng tới hiệu năng. Dù trong trường hợp ảnh hưởng tới hiệu năng thì tùy vào mức độ ảnh hưởng bạn có thể chọn một trong ba cách bên trên để tối ưu. Thậm chí là cả ba cách trong một ứng dụng ở những Component khác nhau.

Bình luận hoặc nhắn tin cho mình nếu bạn có câu hỏi hoặc thắc mắc nào nhé.

Leave a comment