Cara menggunakan metode siklus hidup getDerivedStateFromProps sebagai kebalikan dari componentWillReceiveProps

142

Sepertinya componentWillReceivePropsakan sepenuhnya dihapus dalam rilis mendatang, mendukung metode siklus hidup baru getDerivedStateFromProps: getDerivedStateFromProps statis () .

Setelah diperiksa, sepertinya Anda sekarang tidak dapat membuat perbandingan langsung antara this.propsdan nextProps, seperti yang Anda bisa lakukan componentWillReceiveProps. Apakah ada cara untuk mengatasi ini?

Juga, sekarang mengembalikan objek. Apakah saya benar mengasumsikan bahwa nilai pengembalian pada dasarnya this.setState?

Di bawah ini adalah contoh yang saya temukan online: Negara bagian berasal dari properti / negara bagian .

Sebelum

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

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

Setelah

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;
  }
}
Andrew
sumber

Jawaban:

96

Tentang penghapusan componentWillReceiveProps: Anda harus dapat menangani penggunaannya dengan kombinasi getDerivedStateFromPropsdan componentDidUpdate, lihat Bereaksi blog sebagai contoh migrasi. Dan ya, objek yang dikembalikan oleh getDerivedStateFromPropspembaruan negara mirip dengan objek yang diteruskan setState.

Jika Anda benar-benar membutuhkan nilai prop yang lama, Anda dapat selalu menyimpannya di negara Anda dengan sesuatu seperti ini:

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
  };
}

Apa pun yang tidak mempengaruhi keadaan dapat dimasukkan ke dalam componentDidUpdate, dan bahkan ada getSnapshotBeforeUpdatehal-hal yang sangat rendah.

PEMBARUAN: Untuk merasakan metode siklus hidup yang baru (dan yang lama), paket visualisator siklus hidup dapat membantu.

Oblosys
sumber
1
Ugh, aku mengacaukan pertanyaan itu. Maksud saya sebenarnyacomponentWillReceiveProps
Andrew
2
Saya telah berpikir untuk menggunakan keadaan saya untuk memegang alat peraga sebelumnya, tetapi saya benar-benar ingin menghindari kode tambahan dan logika yang diperlukan untuk mengimplementasikannya. Saya akan melihat beberapa hal lain yang Anda kemukakan. Terimakasih banyak!
Andrew
4
Harus menyimpan prop sebelumnya dalam keadaan hanyalah solusi boilerplate untuk perubahan React API yang sulit dipahami ini. Bagi banyak pengembang, ini terlihat seperti antipattern dan perubahan regresi. Tidak mengkritik Anda Oblosys, tetapi tim Bereaksi.
AxeEffect
2
@AxeEffect Ini karena getDerivedStateFromPropstidak pernah benar-benar dimaksudkan untuk memoisasi . Silakan lihat jawaban saya di bawah di mana saya menggambarkan pendekatan yang direkomendasikan sebagai gantinya.
Dan Abramov
apakah itu salah cetak? Apakah kamu merindukan ...? Itulah yang harus kita kembalikan seluruh objek keadaan atau hanya bagian yang kita pedulikan.
Pemrogram
51

Seperti yang baru-baru ini kami posting di blog Bereaksi , dalam sebagian besar kasus Anda tidak perlu getDerivedStateFromPropssama sekali .

Jika Anda hanya ingin menghitung beberapa data turunan, baik:

  1. Lakukan tepat di dalam render
  2. Atau, jika menghitung ulang biayanya mahal, gunakan pembantu memoisasi seperti memoize-one.

Inilah contoh "setelah" yang paling sederhana:

import memoize from "memoize-one";

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

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

Lihatlah bagian posting blog ini untuk mempelajari lebih lanjut.

Dan Abramov
sumber
45
Jika itu tidak diperlukan dalam sebagian besar kasus, maka saya terkejut ini adalah perubahan yang sangat dibutuhkan, yang akan menghancurkan ribuan proyek kerja. Sepertinya tim React memulai rekayasa.
Ska
39
Ubah dari componentWillReceiveProps ke getDerivedStateFromProps. Itu tidak melanggar tetapi memaksa untuk memperbaiki semua kode yang ada, yang sangat memakan waktu. Dan tampaknya sangat sedikit manfaatnya karena Anda mengatakan Anda tidak boleh menggunakannya sama sekali dalam sebagian besar kasus. Mengapa harus repot-repot mengubah API untuk sesuatu yang seharusnya tidak digunakan di tempat pertama.
Ska
4
Saya akan senang menanggapi komentar dari Dan Abramov ini.
Louis345
6
@DanAbramov ada jawaban mengapa perubahan ini terjadi?
Petros Kyriakou
3
Sebenarnya dalam proyek kami ini banyak digunakan. Untuk menampilkan hal-hal seperti Snackbars di layar ketika data baru turun, 1 contoh. componentWillReceivePropssederhana dan berhasil. Mengapa menghapusnya untuk sampah statis ini ...
Oliver Dixon
6

Seperti yang disebutkan oleh Dan Abramov

Lakukan tepat di dalam render

Kami benar-benar menggunakan pendekatan itu dengan memoise satu untuk segala jenis alat proxy untuk menyatakan perhitungan.

Kode kami terlihat seperti ini

// ./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>
    );
  }
}

Manfaatnya adalah Anda tidak perlu kode ton boilerplate perbandingan di dalam getDerivedStateFromPropsatau componentWillReceivePropsdan Anda dapat melewati inisialisasi salin-tempel di dalam konstruktor.

CATATAN:

Pendekatan ini hanya digunakan untuk proksi alat peraga untuk menyatakan, jika Anda memiliki beberapa logika keadaan dalam, masih perlu ditangani dalam siklus hidup komponen.

mpospelov
sumber