Khái niệm chính về ReactJS: Trạng thái và Vòng đời

Tram Ho

Introduction

Như đã biết ở phần trước, ReactJS có một quy tắc chung là props của component luôn luôn là read-only, vì thế nên để không vi phạm vào quy tắc này, state ra đời.

Cũng giống như props, state cũng có nhiệm vụ chứa các thông tin của component. Tuy nhiên state chỉ hoạt động trong component của nó (private), là thành phần của component, và là loại dữ liệu động (có thể thay đổi được). Nếu 1 component cần quản lý state, thì component đó nên là class component hơn là function component.

Example

Cùng quay trở lại với vd ticking clock ở phần đầu, là một trong những cách để update UI thông qua việc gọi ReactDOM.render() nhiều lần:

Áp dụng kiến thức về Component và Props ở phần trước, ta có thể khởi tạo component Clock và refactor lại vd trên như sau:

Tuy nhiên, ta có thể tối ưu hơn nữa bằng cách để component Clock tự khởi tạo biến date và update chính nó theo thời gian.
Tức là giá trị của date sẽ phải được thay đổi liên tục, điều này sẽ vi phạm đến nguyên tắc read-only của props. Vì vậy chúng ta sẽ cần đến state và sức mạnh của các lifecycle methods.

Việc cần làm đầu tiên, đó là biến Clock từ function component trở thành class component.

Converting a Function to a Class

Để khởi tạo class component, ta sẽ thực hiện lần lượt các bước như sau:

  • tạo 1 ES6 class với tên là Clock, extend React.Component
  • sử dụng method render() bên trong
  • chuyển toàn bộ body của function component cũ vào trong hàm render()
  • sử dụng this.props. thay vì props. như ở function component

Bước tiếp theo chúng ta sẽ sử dụng state để lưu lại giá trị của date cho component Clock.

Adding Local State to a Class

Ta sẽ chuyển date từ props sang state như sau:

Đầu tiên, chuyển this.props.date thành this.state.date ở method render():

Sau đó sử dụng constructor để khởi tạo giá trị date và gán vào state:

Và bỏ props date khỏi element <Clock />:

Cuối cùng ta được:

Demo: Try it on CodePen

Bước tiếp theo chúng ta sẽ sử dụng lifecycle method để update giá trị của date theo thời gian và update lại UI tương ứng.

Adding Lifecycle Methods to a Class

Khi một app sử dụng nhiều component, việc giải phóng tài nguyên bị chiếm dụng bởi các component sau khi các component này bị loại bỏ là điều rất quan trọng.

Cụ thể trong bài toán này, để khởi tạo giá trị cho date và update nó liên tục theo thời gian, ta sẽ sử dụng method đếm setInterval. Tức là setInterval sẽ hoạt động ngay sau khi Clock được render vào DOM lần đầu tiên, trong React điều này được gọi là Mounting. Chúng ta cũng muốn xóa bỏ việc đếm này sau khi Clock bị loại bỏ, quá trình này được gọi là unmounting trong React.

Để làm được những điều đó, chúng ta sẽ thêm các logic tương ứng khi component được mountunmount thông qua 2 method là componentDidMount()componentWillUnmount(). Đây chính là Lifecycle Method trong React:

  • method componentDidMount() được chạy sau khi component output được render ra ngoài DOM
  • method componentWillUnmount() chạy sau khi component bị loại bỏ khỏi DOM

Trở lại với bài toán, chúng ta muốn chạy setInterval ngay sau khi Clock được render, thì ta cần thêm nó vào trong componentDidMount():

Chúng ta đã lưu lại giá trị của timer ID vào this.timerID. Khác với this.props, chúng ta có thể thoải mái khai báo thêm các field ở trong class component Clock để lưu lại các giá trị mà không ảnh hưởng đến luồng chính của logic, vd như this.timerID bên trên.

Tiếp tục, để xóa bỏ quá trình đếm sau khi Clock bị loại bỏ khỏi DOM, ta sẽ sử dụng method clearInterval và cho nó vào trong componentWillUnmount():

Sau đó là tạo function tick(), trong đó sử dụng method this.setState() để set lại giá trị của date mỗi khi tick() được gọi:

Cuối cùng ta được:

Demo: Try it on CodePen

Tổng kết lại ta có luồng xử lí như sau:

  • Khi <Clock /> được truyền vào ReactDOM.render(), React sẽ gọi đến constructor của component Clock sau đó khởi tạo giá trị state là object chứa time hiện tại
  • Sau đó React gọi đến method render() của component Clock và update DOM tương ứng với output của method render()
  • Sau khi output của component Clock được render vào DOM, React sẽ gọi đến lifecycle method componentDidMount(). Lúc này bộ đếm sẽ được khởi tạo và gọi đến method tick() theo thời gian đã set
  • Cứ mỗi lần method tick() được gọi, React biết rằng DOM sẽ thay đổi vì giá trị của this.state.date thay đổi sau khi gọi đến method setState() bên trong. Vì thế nên sau đó React sẽ gọi lại method render() và DOM sẽ được cập nhật
  • Trường hợp component Clock bị remove khỏi DOM, React sẽ gọi đến method componentWillUnmount() để xóa bỏ bộ đếm

Using State Correctly

Do Not Modify State Directly

Chúng ta không nên modify lại giá trị cho state một cách trực tiếp, làm thế thì component tương ứng sẽ không được render lại, vd:

React sẽ trigger việc re-render thông qua method setState(), vì thế nên khi muốn modify giá trị của state, ta nên dùng method setState():

Việc khai báo giá trị cho this.state chỉ được thực hiện ở trong constructor, như vd ticking Clock bên trên.

State Updates May Be Asynchronous

React có thể gộp nhiều lệnh gọi đến setState() vào một batch duy nhất để cải thiện hiệu suất, vì thế nên this.propsthis.state có thể được update một cách bất đồng bộ.

Chúng ta cần chú ý khi sử dụng giá trị của propsstate để tính toán, vd dưới đây có thể sẽ sai trong 1 vài trường hợp:

Để tránh điều này, chúng ta có thể sử dụng dạng khác của method setState(), nhận vào một function thay vì object như thông thường. Function này sẽ nhận state ngay trước đó là tham số đầu tiên, và tham số thứ hai sẽ là giá trị props tại thời điểm việc update đã hoàn thành:

Thay vì dạng arrow function như trên, ta có thể viết dưới dạng regular function:

State Updates are Merged

Bản chất của method setState() là merged object bên trong vào giá trị state hiện tại, vd ta khai báo các field cho state ban đầu như sau:

Sau đó chúng ta có thể update / modified lại từng field một cách độc lập:

Vì là shallow merged, nên this.setState({comments}) sẽ chỉ modified this.state.comments và không đả động gì đến this.state.posts

Summary

Bài viết nhằm giới thiệu về khái niệm State và Lifecycle trong ReactJS, cảm ơn bạn đã dành thời gian theo dõi.

Nguồn: https://reactjs.org/docs/state-and-lifecycle.html

Chia sẻ bài viết ngay

Nguồn bài viết : Viblo