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.counter
bị 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.Component
thì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à
componentName
khô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 false
là 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