Yêu cầu thg 6 23, 2019 2:27 CH 1339 0 1
  • 1339 0 1
0

Component vs Pure.Component

Chia sẻ
  • 1339 0 1

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.

thg 6 23, 2019 2:42 CH

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

thg 6 23, 2019 5:09 CH
Avatar Anh Tran @thanh_tuan
thg 6 24, 2019 2:36 SA

@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

1 CÂU TRẢ LỜI


Đã trả lời thg 6 23, 2019 5:09 CH
Đã được chấp nhận
+12

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 /><PureComponent />. 2 component con này lần lượt sẽ là React.ComponentReact.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 do React.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 
} 
Chia sẻ
Avatar Anh Tran @thanh_tuan
thg 6 24, 2019 2:31 SA

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

thg 6 24, 2019 3:54 SA

@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ới prevProps = 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

Avatar Anh Tran @thanh_tuan
thg 6 24, 2019 4:05 SA
Avatar Anh Tran @thanh_tuan
thg 6 24, 2019 4:09 SA

@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 ? 😄

thg 6 24, 2019 4:44 SA

@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()

thg 6 25, 2019 1:17 SA

@HuyDQ Good job

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí