Cách sử dụng phương thức vòng đời getDerivingStateFromProps trái ngược với thành phầnWillReceiveProps


142

Có vẻ như componentWillReceivePropssẽ được loại bỏ hoàn toàn trong các phiên bản sắp tới, ủng hộ một phương pháp vòng đời mới getDerivedStateFromProps: static getDerivingStateFromProps () .

Khi kiểm tra, có vẻ như bạn hiện không thể so sánh trực tiếp giữa this.propsnextProps, giống như bạn có thể tham gia componentWillReceiveProps. Có cách nào để khắc phục điều này?

Ngoài ra, bây giờ nó trả về một đối tượng. Tôi có đúng không khi cho rằng giá trị trả về cơ bản là this.setState?

Dưới đây là một ví dụ tôi tìm thấy trực tuyến: Trạng thái bắt nguồn từ đạo cụ / trạng thái .

Trước

class ExampleComponent extends React.Component {
  state = {
    derivedData: computeDerivedState(this.props)
  };

  componentWillReceiveProps(nextProps) {
    if (this.props.someValue !== nextProps.someValue) {
      this.setState({
        derivedData: computeDerivedState(nextProps)
      });
    }
  }
}

Sau

class ExampleComponent extends React.Component {
  // Initialize state in constructor,
  // Or with a property initializer.
  state = {};

  static getDerivedStateFromProps(nextProps, prevState) {
    if (prevState.someMirroredValue !== nextProps.someValue) {
      return {
        derivedData: computeDerivedState(nextProps),
        someMirroredValue: nextProps.someValue
      };
    }

    // Return null to indicate no change to state.
    return null;
  }
}

Câu trả lời:


96

Về việc loại bỏ componentWillReceiveProps: bạn sẽ có thể xử lý việc sử dụng nó với sự kết hợp của getDerivedStateFromPropscomponentDidUpdate, xem bài đăng trên blog React để biết ví dụ về việc di chuyển. Và đúng vậy, đối tượng được trả về bằng cách getDerivedStateFromPropscập nhật trạng thái tương tự như một đối tượng được truyền cho setState.

Trong trường hợp bạn thực sự cần giá trị cũ của một chỗ dựa, bạn luôn có thể lưu trữ nó trong trạng thái của mình bằng một cái gì đó như thế này:

state = {
  cachedSomeProp: null
  // ... rest of initial state
};

static getDerivedStateFromProps(nextProps, prevState) {
  // do things with nextProps.someProp and prevState.cachedSomeProp
  return {
    cachedSomeProp: nextProps.someProp,
    // ... other derived state properties
  };
}

Bất cứ điều gì không ảnh hưởng đến nhà nước đều có thể được đưa vào componentDidUpdate, và thậm chí còn có một thứ getSnapshotBeforeUpdaterất thấp.

CẬP NHẬT: Để cảm nhận về các phương pháp vòng đời mới (và cũ), gói phản ứng vòng đời phản ứng có thể hữu ích.


1
Ugh, tôi nhầm lẫn câu hỏi. Tôi thực sự có nghĩa làcomponentWillReceiveProps
Andrew

2
Tôi đã nghĩ đến việc sử dụng trạng thái của mình để giữ các đạo cụ trước đó, nhưng tôi thực sự muốn tránh các mã bổ sung và logic cần có để thực hiện nó. Tôi sẽ xem xét một số thứ khác mà bạn đưa lên. Cảm ơn rất nhiều!
Andrew

4
Phải lưu trữ một chỗ dựa trước đó trong trạng thái chỉ là một cách giải quyết cho sự thay đổi API React khó hiểu này. Đối với con mắt của nhiều nhà phát triển, nó trông giống như một phản hạt và thay đổi hồi quy. Không chỉ trích bạn Oblosys, mà là nhóm React.
AxeEffect

2
@AxeEffect Điều này là do getDerivedStateFromPropskhông bao giờ thực sự có ý định ghi nhớ . Xin vui lòng xem câu trả lời của tôi dưới đây, nơi tôi mô tả phương pháp được đề nghị thay thế.
Dan Abramov

đó có phải là một lỗi đánh máy không? Bạn đã bỏ lỡ ...? Đó là chúng ta nên trả lại toàn bộ đối tượng trạng thái hoặc chỉ phần mà chúng ta quan tâm.
theprogrammer

51

Như chúng tôi đã đăng gần đây trên blog React , trong phần lớn các trường hợp bạn không cần getDerivedStateFromPropsgì cả .

Nếu bạn chỉ muốn tính toán một số dữ liệu dẫn xuất, một trong hai:

  1. Làm ngay bên trong render
  2. Hoặc, nếu tính lại nó là tốn kém, hãy sử dụng một trình trợ giúp ghi nhớ như thế nào memoize-one.

Đây là ví dụ "sau" đơn giản nhất:

import memoize from "memoize-one";

class ExampleComponent extends React.Component {
  getDerivedData = memoize(computeDerivedState);

  render() {
    const derivedData = this.getDerivedData(this.props.someValue);
    // ...
  }
}

Kiểm tra phần này của bài viết trên blog để tìm hiểu thêm.


45
Nếu nó không cần thiết trong phần lớn các trường hợp, thì tôi ngạc nhiên rằng đây là một sự thay đổi rất cần thiết, một trong những dự án sẽ phá vỡ hàng ngàn dự án đang hoạt động. Có vẻ như nhóm React đã bắt đầu kỹ thuật.
Ska

39
Thay đổi từ thành phầnWillReceiveProps thành getDerivingStateFromProps. Nó không phá vỡ nhưng buộc phải cấu trúc lại tất cả các mã hiện có, điều này rất tốn thời gian. Và dường như rất ít lợi ích vì bạn nói rằng bạn không nên sử dụng nó trong phần lớn các trường hợp. Tại sao phải trải qua rắc rối thay đổi API cho thứ gì đó thậm chí không được sử dụng ngay từ đầu.
Ska

4
Tôi rất thích một phản hồi cho nhận xét này từ Dan Abramov.
Louis345

6
@DanAbramov có câu trả lời nào về lý do tại sao sự thay đổi này xảy ra không?
Petros Kyria Khẩu

3
Trên thực tế trong các dự án của chúng tôi điều này được sử dụng rất nhiều. Để hiển thị những thứ như Snackbars trên màn hình khi dữ liệu mới xuất hiện, 1 ví dụ. componentWillReceivePropsđơn giản và nó đã làm việc Tại sao phải loại bỏ nó cho rác tĩnh này ...
Oliver Dixon

6

Như Dan Abramov đã đề cập

Làm điều đó ngay bên trong kết xuất

Chúng tôi thực sự sử dụng cách tiếp cận đó với một trong những loại đạo cụ ủy quyền để tính toán trạng thái.

Mã của chúng tôi trông như thế này

// ./decorators/memoized.js  
import memoizeOne from 'memoize-one';

export function memoized(target, key, descriptor) {
  descriptor.value = memoizeOne(descriptor.value);
  return descriptor;
}

// ./components/exampleComponent.js
import React from 'react';
import { memoized } from 'src/decorators';

class ExampleComponent extends React.Component {
  buildValuesFromProps() {
    const {
      watchedProp1,
      watchedProp2,
      watchedProp3,
      watchedProp4,
      watchedProp5,
    } = this.props
    return {
      value1: buildValue1(watchedProp1, watchedProp2),
      value2: buildValue2(watchedProp1, watchedProp3, watchedProp5),
      value3: buildValue3(watchedProp3, watchedProp4, watchedProp5),
    }
  }

  @memoized
  buildValue1(watchedProp1, watchedProp2) {
    return ...;
  }

  @memoized
  buildValue2(watchedProp1, watchedProp3, watchedProp5) {
    return ...;
  }

  @memoized
  buildValue3(watchedProp3, watchedProp4, watchedProp5) {
    return ...;
  }

  render() {
    const {
      value1,
      value2,
      value3
    } = this.buildValuesFromProps();

    return (
      <div>
        <Component1 value={value1}>
        <Component2 value={value2}>
        <Component3 value={value3}>
      </div>
    );
  }
}

Lợi ích của nó là bạn không cần mã hàng tấn so sánh bên trong getDerivedStateFromPropshoặc componentWillReceivePropsbạn có thể bỏ qua việc khởi tạo sao chép-dán bên trong một hàm tạo.

GHI CHÚ:

Cách tiếp cận này chỉ được sử dụng để ủy quyền cho các đạo cụ ở trạng thái, trong trường hợp bạn có một số logic trạng thái bên trong, nó vẫn cần được xử lý trong các vòng đời thành phần.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.