Come utilizzare il metodo del ciclo di vita getDerivedStateFromProps rispetto a componentWillReceiveProps


142

Sembra componentWillReceivePropsche verrà gradualmente eliminato nelle prossime versioni, a favore di un nuovo metodo del ciclo di vita getDerivedStateFromProps: statico getDerivedStateFromProps () .

Al momento dell'ispezione, sembra che ora non sia possibile effettuare un confronto diretto tra this.propse nextProps, come è possibile componentWillReceiveProps. C'è un modo per aggirare questo?

Inoltre, ora restituisce un oggetto. È corretto supporre che il valore di ritorno sia essenzialmente this.setState?

Di seguito è riportato un esempio che ho trovato online: Stato derivato da oggetti di scena / stato .

Prima

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

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

Dopo

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

Risposte:


96

Informazioni sulla rimozione di componentWillReceiveProps: dovresti essere in grado di gestirne gli usi con una combinazione di getDerivedStateFromPropse componentDidUpdate, vedi il post sul blog di React, ad esempio le migrazioni. E sì, l'oggetto restituito getDerivedStateFromPropsaggiorna lo stato in modo simile a un oggetto passato setState.

Nel caso in cui tu abbia davvero bisogno del vecchio valore di un oggetto, puoi sempre memorizzarlo nel tuo stato con qualcosa del genere:

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

Tutto ciò che non influisce sullo stato può essere inserito componentDidUpdatee c'è anche un getSnapshotBeforeUpdatemateriale di livello molto basso.

AGGIORNAMENTO: per avere un'idea dei nuovi (e vecchi) metodi del ciclo di vita, il pacchetto di reazione-ciclo di vita-visualizzatore può essere utile.


1
Ugh, ho incasinato la domanda. In realtà intendevocomponentWillReceiveProps
Andrew,

2
Avevo pensato di usare il mio stato per contenere oggetti di scena precedenti, ma volevo davvero evitare il codice e la logica extra necessari per implementarlo. Esaminerò alcune delle altre cose che tiri fuori. Molte grazie!
Andrew,

4
Dover memorizzare un prop precedente in uno stato è solo una soluzione alternativa per questa modifica API React difficile da capire. Agli occhi di molti sviluppatori questo sembra un antipasto e un cambiamento di regressione. Non ti sto criticando Oblosys, ma il team di React.
AxeEffect,

2
@AxeEffect Questo perché getDerivedStateFromPropsnon è mai stato concepito per la memoizzazione . Si prega di vedere la mia risposta qui sotto in cui ho descritto l'approccio raccomandato invece.
Dan Abramov,

è un errore di battitura? Ti sei perso ...? Cioè dovremmo restituire l'intero oggetto stato o solo la parte che ci interessa.
programmatore il

51

Come abbiamo recentemente pubblicato sul blog di React , nella stragrande maggioranza dei casi non è necessario getDerivedStateFromPropsaffatto .

Se vuoi solo calcolare alcuni dati derivati, o:

  1. Fallo proprio dentro render
  2. Oppure, se il ricalcolo è costoso, utilizzare un aiutante di memoization come memoize-one.

Ecco l'esempio "dopo" più semplice:

import memoize from "memoize-one";

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

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

Dai un'occhiata a questa sezione del post sul blog per saperne di più.


45
Se non è necessario nella stragrande maggioranza dei casi, sono sorpreso che si sia trattato di un cambiamento così gravemente necessario, che interromperà migliaia di progetti di lavoro. Sembra che il team di React abbia ricominciato a progettare.
Ska,

39
Passa da componentWillReceiveProps a getDerivedStateFromProps. Non si sta rompendo, ma forzando il refactoring di tutto il codice esistente, il che richiede molto tempo. E sembra avere pochissimi benefici poiché dici che non dovresti usarlo affatto nella stragrande maggioranza dei casi. Perché passare attraverso la seccatura di cambiare API per qualcosa che non dovrebbe nemmeno essere usato in primo luogo.
Ska,

4
Mi piacerebbe una risposta a questo commento di Dan Abramov.
Louis345,

6
@DanAbramov qualche risposta sul perché si è verificato questo cambiamento?
Petros Kyriakou,

3
In realtà nei nostri progetti questo è molto usato. Per mostrare cose come le Snackbar sugli schermi per quando arrivano nuovi dati, 1 esempio. componentWillReceivePropsera semplice e ha funzionato. Perché rimuoverlo per questa spazzatura statica ...
Oliver Dixon,

6

Come menzionato da Dan Abramov

Fallo nel rendering interno

In realtà usiamo quell'approccio con memoise one per qualsiasi tipo di propulsione proxy per dichiarare i calcoli.

Il nostro codice appare così

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

I vantaggi di ciò sono che non è necessario codificare tonnellate di piastre di confronto all'interno getDerivedStateFromPropsoppure componentWillReceivePropsè possibile saltare l'inizializzazione di copia e incolla all'interno di un costruttore.

NOTA:

Questo approccio viene utilizzato solo per indicare agli oggetti di scena di dichiarare, nel caso in cui si disponga di una logica di stato interna, è comunque necessario gestirli nei cicli di vita dei componenti.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.