Component vs Pure.Component
Mọi người có thể phân biệt giúp mình hai thằng trên được không ạ.
Thực sự là mình cung tìm hiểu qua trên Google rồi nhưng vân chưa phân biệt được gặp trường hợp nào thì nên dùng Pure.Component thay thế component
Mn có thể cho mình xin một ví dụ về nó được không.
1 CÂU TRẢ LỜI
Như bạn biết trong lifecycle của React có một function tên là shouldComponentUpdate() dùng để kiểm tra xem có tiến hành re-render lại component đó không. Với Component thông thường thì mặc định function này sẽ luôn trả về true đồng nghĩa với việc component của bạn sẽ được re-render lại kể cả khi không có sự thay đổi về state hay props của nó. Để rõ hơn bạn có thể xem ví dụ sau:
class App extends React.Component {
state = {
firstComponentName: "DefaultComponent",
secondComponentName: "PureComponent",
counter: 0
};
handleIncrement = () => {
this.setState(prevState => ({
counter: prevState.counter + 1
}));
};
render() {
return (
<div className="App">
<p>You click: {this.state.counter} time</p>
<DefaultComponent componentName={this.state.firstComponentName} />
<PureComponent componentName={this.state.secondComponentName} />
<button onClick={this.handleIncrement}>Increment</button>
</div>
);
}
}
class DefaultComponent extends React.Component {
componentDidUpdate() {
console.log("Re-render DefaultComponent");
}
render() {
return <h1>{this.props.componentName}</h1>;
}
}
class PureComponent extends React.PureComponent {
componentDidUpdate() {
console.log("Re-render PureComponent");
}
render() {
return <h1>{this.props.componentName}</h1>;
}
}
Như bạn thấy ở đây mình có 1 component cha là <App /> và 2 component con là <DefaultComponent /> và <PureComponent />. 2 component con này lần lượt sẽ là React.Component và React.PureComponent và nhận vào props và componentName từ component <App />. Trong mỗi component mình đã thêm hàm componentDidUpdate() và console.log ra nếu component đó bị re-render. Ngoài ra thì component <App /> còn có một state là counter và một nút cho phép tăng giá trị này lên. Mỗi khi ta bấm nút đó thì sẽ những thứ sẽ xảy ra như sau:
state.counterbị thay đổi - cộng thêm một vào giá trị ban đầu- Việc thay đổi state này sẽ dẫn đến component
<App />bị render lại - Dẫn đến
<DefaultComponent />cũng bị render lại doReact.ComponentthìshouldComponentUpdate()luôn trả về true. <PureComponent />không bị render lại (bạn có thể check phần console.log() để biết phần nào bị render lại- Hết =))
Sở dĩ component PureComponent không bị re-render là do hàm shouldComponentUpdate() của nó không mặc định trả về true mà ở đây nó tự động thực hiện cái gọi là shallow compare. Cụ thể nó sẽ so sánh dạng như sau:
shouldComponentUpdate(nextProps, nextState) {
return this.props.componentName !== nextProps.componentName
}
- Do ở đây prop ta truyền vào là
componentNamekhông hề bị thay đổi nên hàm này sẽ trả về false và component này sẽ không bị re-render này. Link demo: https://codesandbox.io/s/component-vs-purecomponent-fqv1x
Hi @HuyDQ bạn giải thích rất dễ hiểu, mình cám ơn bạn nha.
Bạn cho mình hỏi, có trường hợp thế này thì xử lý thế nào nha. Đại khái là mình không muốn render() lại child-component.
Pure.Component trong ví dụ dưới đây là chịu chết rồi.
Với trường hợp sử dụng component bình thường với Class thì mình có thể prevent nó bằng hàm shouldComponentUpdate
Còn với component viết bằng function mình chưa biết xử lý ra sao.
Bạn xem qua code rồi giúp đỡ m chỗ này vs : https://codesandbox.io/s/angry-hamilton-nxfc8
Trong Parent component m đang dùng ChildClass bạn thay bằng ChildFunc để test thử nhé.
tks bạn nhiều
@thanh_tuan ở đây bạn đã biết sử dụng React.memo rồi mà nhỉ
). Chắc bạn chưa đọc kĩ API này vì React.memo sẽ nhận vào 2 tham số là function component của bạn và một hàm có tác dụng giống như shouldComponentUpdate() như sau:
import React, { useState } from "react";
const ChildFunc = React.memo(
props => {
console.log("rendering children Function !!!");
const [state, setState] = useState({ count: 0 });
const incrementChild = () => {
const newCount = state.count + props.progressive;
setState({ count: newCount });
};
return (
<div>
<div>Child-value: {state.count}</div>
<button onClick={incrementChild}>++</button>
</div>
);
},
(prevProps, nextProps) => {
return true;
}
);
export default ChildFunc;
Như bạn có thể thấy ở đây mình chuyền được thêm vào một function thứ 2 là:
(prevProps, nextProps) => {
return true;
}
Tuy nhiên ở đây lại ngược lại với shouldComponentUpdate() là:
- Nếu
return trueđồng nghĩa vớiprevProps = nexProps=> Component sẽ không được re-render lại - Nếu
return falselà ngược lại
Bạn có thể đọc lại tại đây https://reactjs.org/docs/react-api.html#reactmemo
@HuyDQ ủa nếu vậy trường hợp của mình phải đặt là return false mới đúng chứ nhỉ.
Mà nếu đặt là false thì tức là cho render() lại nhưng giờ bấm vào button ở Parent nó lại ko bị render() lại nữa nhỉ ? Hay thật nhưng mà đoạn này chưa hiểu vì sao ? 
@thanh_tuan mình return true để demo thôi còn ở đây bạn có thể thêm các điều kiện để check như trong shouldComponentUpdate()
@HuyDQ Good job
Hiểu đơn giản là khi bạn có một ListItem và chỉ khi muốn update một item trong đó thì nên sử dụng PureComponent làm list đó, khi đó sẽ chỉ render lại item thay đổi chứ không render lại cả ListItem này.
Ví dụ bạn có 1 list sản phẩm khi click nào sản phẩm nào thì sẽ hiện phía bên phải màn hình, bỏ đi thì nó mất đi.
Với cách giải thích này mình mong bạn đã hiểu nên sử dụng PureComponent khi nào
@longnk1301 m thực sự là vẫn chưa hình dung được ý của bạn nhưng dù sao vẫn cảm ơn bạn nha