web-dev-qa-db-fra.com

composantWillReceiveProps vs getDerivedStateFromProps

Quels composants exactementWillReceiveProps et getDerivedStateFromProps sont une question subtile pour moi. En effet, je viens de rencontrer un problème lors de l'utilisation de getDerivedStateFromProps:

// Component 
state = {
  myState: []
}

// Using this method works fine:

componentWillReceiveProps(nextProps) {
  this.setState({
    myState: nextProps.myPropsState
  })
}

// But using this method will cause the checkboxes to be readonly:

static getDerivedStateFromProps(nextProps,prevProps) {
  const { myPropsState: myState } = nextProps
  return {
    myState
  }
}

// And here's checkbox
<input type="checkbox" id={`someid`} 
 onChange={(e) => this.handleMethod(e, comp.myState)} 
 checked={myState.indexOf(comp.myState) > -1} />

React version: 16.4.1

4
Bhojendra Rauniyar

Enfin, j'ai résolu mon problème. C'était un débogage douloureux:

// Child Component

// instead of this
// this.props.onMyDisptach([...myPropsState])

// dispatching true value since myPropsState contains only numbers
this.props.onMyDispatch([...myPropsState, true])

En effet, j’ai deux conditions: 1) changer de case à cocher (composant) 2) appuyer sur le bouton de réinitialisation (composant enfant)

J'avais besoin de réinitialiser les états lorsque le bouton de réinitialisation est enfoncé. Ainsi, lors de l'envoi de l'état aux accessoires pour le bouton de réinitialisation, j'ai utilisé une valeur booléenne pour savoir qu'il s'agit d'un changement par rapport à la réinitialisation. Vous pouvez utiliser ce que vous voulez, mais vous devez en tenir compte.

Maintenant, ici dans le composant, j'ai trouvé quelques indices sur les différences entre composantWillReceiveProps et getDerivedStateFromProps après le débogage de la sortie de la console.

// Component
static getDerivedStateFromProps(props, state) {
    const { myPropsState: myState } = props
    // if reset button is pressed
    const true_myState = myState.some(id=>id===true)
    // need to remove true value in the store
    const filtered_myState = myState.filter(id=>id!==true)
    if(true_myState) {
      // we need to dispatch the changes to apply on its child component
      // before we return the correct state
      props.onMyDispatch([...filtered_myState])
      return {
        myState: filtered_myState
      }
    }
    // obviously, we need to return null if no condition matches
    return null
  }

Voici ce que j'ai trouvé les résultats de la sortie de la console:

  • getDerivedStateFromProps enregistre immédiatement chaque changement d'accessoire

  • composantWillReceiveProps enregistre uniquement après que l'enfant a propagé les modifications d'accessoires

  • getDerivedStateFromProps ne répond pas aux modifications d'accessoires (je voulais dire pour les modifications de répartition comme dans l'exemple de code)

  • composantWillReceiveProps répond aux modifications d'accessoires

  • Par conséquent, nous devions fournir les modifications apportées au composant enfant lors de l'utilisation de getDerivedStateFromProps.

Le processus de collage de la valeur vraie dans l'état dont j'ai besoin, car getDerivedStateFromProps gère toutes les modifications contrairement à composantWillReceiveProps, qui gère uniquement le composant enfant qui distribue les modifications aux accessoires.

En passant, vous pouvez utiliser la propriété personnalisée pour vérifier si elle est modifiée et mettre à jour la valeur si getDerivedStateFromProps mais pour une raison quelconque, je dois modifier cette technique.

Il y a peut-être une certaine confusion dans mon libellé mais j'espère que vous l'obtiendrez.

0
Bhojendra Rauniyar

getDerivedStateFromProps n'est pas une alternative directe à componentWillReceiveProps, uniquement en raison du fait qu'il est appelé après chaque mise à jour, qu'il s'agisse d'un changement d'état, d'un changement d'accessoire ou d'une nouvelle restitution du parent.

Quoi qu'il en soit, simplement renvoyer l'état de getDerivedStateFromProps n'est pas la bonne façon, vous devez comparer l'état et les accessoires avant de renvoyer la valeur. Sinon, à chaque mise à jour, l'état est réinitialisé et le cycle se poursuit

Selon les docs

getDerivedStateFromProps est invoqué juste avant d'appeler le rendu méthode, à la fois sur le montage initial et sur les mises à jour ultérieures. Cela devrait renvoyer un objet pour mettre à jour l'état ou null pour ne rien mettre à jour.

Cette méthode existe pour les cas d'utilisation rares où l'état dépend de changements d'accessoires au fil du temps. Par exemple, cela pourrait être pratique pour implémenter un composant <Transition> qui compare son précédent et ensuite aux enfants de décider lequel d’entre eux animer.

La dérivation de l'état mène au code prolixe et rend vos composants difficile à penser. Assurez-vous que vous maîtrisez la simplicité alternatives:

Si vous devez effectuer un effet secondaire (par exemple, l'extraction de données Ou une animation) en réponse à un changement d'accessoire, utilisez componentDidUpdate cycle de vie à la place.

Si vous voulez recalculer certaines données uniquement lorsqu'un accessoire change, utilisez un assistant memoization à la place.

Si vous voulez "réinitialiser" un état lorsqu'un accessoire change, considérez soit en créant un composant fully controlled ou fully uncontrolled with a key instead.

P.S. Notez que les arguments de getDerivedStateFromProps sont props et state et non nextProps andprevProps`.

Pour entrer dans plus de détails, 

Afin d'apporter des modifications en fonction des accessoires, nous devons stocker prevPropsState dans son état afin de détecter les modifications. Une implémentation typique ressemblerait à

static getDerivedStateFromProps(props, state) {
    // Note we need to store prevPropsState to detect changes.
    if (
      props.myPropsState !== state.prevPropsState
    ) {
      return {
        prevPropsState: state.myState,
        myState: props.myPropsState
      };
    }
    return null;
  }
2
Shubham Khatri

Parmi les documents de réaction:

Notez que cette méthode est déclenchée à chaque rendu, quelle qu'en soit la cause. Cela contraste avec UNSAFE_componentWillReceiveProps, qui ne se déclenche que lorsque le parent provoque un re-rendu et non à la suite d'une setState locale.

Après avoir appelé setState(), vous annulez votre état avec les accessoires actuels. Ainsi, lorsque vous cochez une case, (e) => this.handleMethod(e, comp.myState) est appelé, à savoir des appels supposés, setState(), pour mettre à jour l'état coché de la case à cocher. Mais après cette getDerivedStateFromProps() sera appelée (before render) qui annule ce changement. C'est pourquoi la mise à jour inconditionnelle de l'état des accessoires est considérée comme un anti-modèle .

0
trixn