Lifecycle Hook trong React 16.3
Khi chúng ta làm việc với React hoặc tìm hiểu kỹ hơn về React Component, ta thường xuyên gặp các phương thức như : componentDidMount(), componentDidUpdate(), componentWillUnmount()...Đó chính là các React Lifecycle Methods - Các phương thức vòng đời của React. Khi bạn extends React.Component khi khởi tạo 1 class trong React. Chúng ta sẽ override các method lifecycle này để thực thi một số công việc nhất định. Do đó việc hiểu biết cách làm việc của các Method Lifecycle là rất quan trọng.
Từ phiên bản 16.3 trở đi, React lifecycle đã có một số thay đổi mới, tuy nhiên vẫn hỗ trợ lifecycle cũ cho đến khi ra mắt React 17.
Chúng ta cần trải qua các giai đoạn hay còn gọi là các phase - theo thuật ngữ của React. Các giai đoạn đó bao gồm :
1. Mouting (Sinh ra)
2. Updating (Lớn lên)
3. Unmouting (Chết đi)
Sơ đồ trong version cũ sẽ như sau :
Ở lifecycle cũ phát sinh nhiều vấn đề nhất là naming của lifecycle hook, gây hiểu nhầm. Người ta thường dùng constructor componentWillMount
comonentWillReceiveProps để init state dựa trên props, Vì vậy nhiều khi gây duplicate code. Đó là lý do mà getDerivedStateFromProps sinh ra
để xoá sự khó hiểu và lằng nhằng đó đi. Vì thế trong bài viết này mình sẽ chỉ trình bày các method trong version mới.
1. Các phương thức trong phase Mouting (Sinh ra)
constructor → getDerivedStateFromProps → render → componentDidMount.
a. Constructor(props): void
Ở ES6 thì thường sử dụng để tạo init state, bind context(this) cho các function, event handling, createRef().
Component kế thừa từ React.Component, nên chúng ta cần phải gọi hàm super(props) để gọi đến hàm khởi tạo của thằng cha React.Component. Nếu thiếu thì this.props sẽ là undefined
Ví dụ :
class DemoComponent extends React.Component {
constructor(props) {
super(props);
this.state = {};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState({});
}
render() {
return (
<button onClick={this.handleClick}>Click</button>
);
}
}
b. static getDerivedStateFromProps(props, state): object
Trước đây trong lifecycle cũ, người ta thường thông qua props ở contructor để tính toán state. Khi component update new props, lúc này comonentWillReceiveProps sẽ được gọi để set lại state.
Ví dụ với lifecycle cũ như sau :
class DemoComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
fullName: `${props.lastName} ${props.firstName}`,
};
}
componentWillReceiveProps(nextProps, state) {
this.setState({ fullName: `${nextProps.lastName} ${nextProps.firstName}` });
}
...
}
Vậy khi ta sử dụng lifecycle mới sẽ trông như thế nào
class DemoComponent extends React.Component {
state = {};
static getDerivedStateFromProps(props, state) {
return {
fullName: `${props.lastName} ${props.firstName}`,
};
}
...
}
Khi comonentWillReceiveProps bị xóa bỏ, chúng ta cần 1 method khác để thực thi việc cập nhật state thông qua new props.
=> Hàm static getDerivedStateFromProps. Hàm này được định nghĩa và khai báo là 1 hàm static, vì thế ta không thể sử dụng phương thức this.setState
Vậy, chúng ta cập nhật lại state bằng cách nào ? Câu trả lời là chúng ta sẽ không làm như vậy. Function sẽ trả về state được cập nhật, hoặc null nếu không có cập nhật nào cần thiết.
c. render()
Đây là phương thức duy nhất bắt buộc phải có đối với React Component và có cấu trúc như sau:
render() {
return (
/* Định nghĩa cấu trúc Component tại đây */
)
}
Phương thức này dùng để miêu tả cấu trúc của Component sau khi nó được chèn vào DOM tree. Nó bắt buộc được gọi lần đầu tiên để chèn Component vào HTML, và có thể được gọi lại để cập nhật giao diện mỗi khi state của Component thay đổi.
Đặc biệt, bạn nên để phương thức này là Pure Function – nghĩa là nó không làm thay đổi state của Component, không tương tác với trình duyệt, không lấy dữ liệu từ server,…
Chỉ đơn giản là nó lấy data từ this.props và this.state để xây dựng và cập nhật giao diện.
d. componentDidMount(prevProps, prevState): void
Phương thức componentDidMount() được gọi một lần duy nhất ngay sau khi Component được render xong.
Chính vì tính chỉ được gọi một lần duy nhất nên bên trong phương thức này, mình có thể:
- Lấy dữ liệu từ server để cập lại state cho Component.
- Định nghĩa interval thông qua setInterval để thực hiện một số nhiệm vụ lặp lại.
- Lấy thông tin liên quan đến DOM node như kích thước thực tế (width, height) – vì lúc này chúng đã được hiển thị lên màn hình.
- Đăng ký sự kiện: resize, scroll,…
2. Các phương thức trong phase Updating (Lớn lên)
getDerivedStateFromProps → shouldComponentUpdate → render → getSnapshootBeforeUpdate → componentDidUpdate.
a. static getDerivedStateFromProps(nextProps, state): object
Khi props hoặc state thay đổi thì hook này được gọi.
Ở phiên bản 16.3.x state thay đổi thì hook này không được gọi)
b. shouldComponentUpdate(nextProps, nextState): boolean
- Khi props hoặc state thay đổi thì hook này được gọi.
- Với React.PureComponent thì chúng ta không thể override.
- Với React.Component thì chúng ta có thể override để chống render không cần thiết.
Nếu xác định component này chỉ render 1 lần thì return false, chống render(Đối với React.Component).
c. getSnapshootBeforeUpdate(prevProps, prevState): object
Thường thì get một số thông tin của props, state, hoặc ref trước khi re-render, và sử dụng nó sau khi render.
d. componentDidUpdate(prevProps, prevState, snapshoot): void
- Lúc này đã re-render, thích hợp để tương tác với Tree Node.
- Với lifecycle mới thì có thêm param snapshoot, snapshoot là output của getSnapshootBeforeUpdate hook.
3. Các phương thức trong phase Unmouting (Chết đi)
componentWillUnmount.
a. componentWillUnmount: void
- Thường thì chạy một function nào đó, ví dụ như clear interval, delete rác. Ít khi sử dụng.
- Không nên setState tại đây
4. Kết luận
Trên đây là một số thay đổi trong hook lifecycle mới. Hy vọng mới những gì mình trình bày, các bạn có thể hiểu được những điểm mới mẻ trong version react 16.3 và áp dụng nó trong project của mình.