web-dev-qa-db-fra.com

Comparaison de PrevProps dans componentDidUpdate

Je perds la tête. Peut-être que tu peux m'aider. J'essaie de détecter quand un accessoire a changé à l'intérieur de componentDidUpdate d'un composant monté. Cela a bien fonctionné dans le passé. J'ai même un test (refreshData dans le code ci-dessous) qui fonctionne bien. Est-il possible de SOMEHOW passer des accessoires d'une manière qui n'est pas détectée par componentDidUpdate(prevProps) ??

dans component.js:

componentDidUpdate(prevProps){

    //works fine
    if ( this.props.refreshData !== prevProps.refreshData ) {
        if ( this.props.refreshData )
            this.refreshData();
    }

    //these two arent calling
    if ( this.props.selectedCountries !== prevProps.selectedCountries ) {
        if ( this.props.selectedCountries )
            console.log('updated selected countries');
    }

    if ( this.props.selectedLocations !== prevProps.selectedLocations ) {
        console.log('updated selected locations');
    }

}

et dans App.js en passant les accessoires comme:

selectLocation = (id, type, lng, lat, polydata, name, clear = false) => {

  //console.log(type);
  //console.log(lng);
  //console.log(lat);
  //console.log(polydata);

  let selectedType = 'selected' + type;
  let previousState = [];

  if (clear) {
    this.setState({
      selectedCountries: [],
      selectedLocations: [],
      selectedServices: [],
      selectedPoints: [],
      mapCenter: [lng, lat],
      locationGeoCoords: [polydata]
    })
    previousState.Push(id);

  } else {

    previousState = this.state[selectedType];
    if (previousState.indexOf(id) === -1) {
      //Push id
      previousState.Push(id);

    } else {
      //remove id
      var index = previousState.indexOf(id)
      previousState.splice(index, 1);
    }
  }

  if (type === "Countries") {

    this.setState({
      selectedCountries: previousState,
      refreshData: true,
    })
  } else if (type === "Locations") {
    this.setState({
      selectedLocations: previousState,
      refreshData: true
    })
  } else if (type === "Points") {
    this.setState({
      selectedPoints: previousState,
      refreshData: true
    })
  }


}


render() {
  return (

    <component
      selectedCountries={this.state.selectedCountries}
      selectedLocations={this.state.selectedLocations}
      refreshData={this.state.refreshData} />
  }
}
6
barrylachapelle

Salut :), comme indiqué dans mon commentaire, le problème se trouve dans votre fichier App.js - vous mutez un tableau. En d'autres termes, lorsque vous pensez que vous créez un nouveau tableau de pays sélectionnés à transmettre, vous mettez à jour le tableau d'origine, et donc lorsque vous allez faire une comparaison, vous comparez TOUJOURS les deux mêmes tableaux exacts.

Essayez de mettre à jour votre App.js comme ça -

selectLocation = (id, type, lng, lat, polydata, name, clear = false) => {

  //console.log(type);
  //console.log(lng);
  //console.log(lat);
  //console.log(polydata);

  let selectedType = 'selected' + type;
  let previousState = [];

  if (clear) {
    this.setState({
      selectedCountries: [],
      selectedLocations: [],
      selectedServices: [],
      selectedPoints: [],
      mapCenter: [lng, lat],
      locationGeoCoords: [polydata]
    })
    previousState.Push(id);

  } else {

    previousState = [].concat(this.state[selectedType]);
    if (previousState.indexOf(id) === -1) {
      //Push id
      previousState.Push(id);

    } else {
      //remove id
      var index = previousState.indexOf(id)
      previousState.splice(index, 1);
    }
  }

  if (type === "Countries") {

    this.setState({
      selectedCountries: previousState,
      refreshData: true,
    })
  } else if (type === "Locations") {
    this.setState({
      selectedLocations: previousState,
      refreshData: true
    })
  } else if (type === "Points") {
    this.setState({
      selectedPoints: previousState,
      refreshData: true
    })
  }


}


render() {
  return (

    <component
      selectedCountries={this.state.selectedCountries}
      selectedLocations={this.state.selectedLocations}
      refreshData={this.state.refreshData} />
  }
}

La seule différence est la ligne où vous définissez previousState - je l'ai mis à jour pour être

previousState = [].concat(this.state[selectedType]);

En ajoutant le [].concat, Je crée effectivement un NOUVEAU tableau à chaque fois et donc lorsque vous appliquez vos modifications au tableau via Push/splice vous ne modifierez que le NOUVEAU tableau. Ensuite, la comparaison fonctionnera correctement une fois que vous l'avez transmise comme accessoire :)

Pour votre intérêt de lecture, j'ai trouvé un article qui en parle un peu: https://medium.com/pro-react/a-brief-talk-about-immutability-and-react-s-helpers- 70919ab8ae7c

6
Rose Robertson

selectedCountries et selectedLocations sont des objets de tableau. La référence n'en change jamais. Vérifiez plutôt la longueur.

componentDidUpdate(prevProps){

    if ( this.props.refreshData !== prevProps.refreshData ) {
        if ( this.props.refreshData )
            this.refreshData();
    }

    if ( this.props.selectedCountries.length > prevProps.selectedCountries.length ) {
        if ( this.props.selectedCountries )
            console.log('updated selected countries');
    }

    if ( this.props.selectedLocations.length > prevProps.selectedLocations.length ) {
        console.log('updated selected locations');
    }
}

Dans l'extrait de code ci-dessus, vous semblez apporter des modifications à this.state directement. L'État doit être immuable. Assurez-vous toujours que vous concat pour ajouter et filter pour supprimer les éléments car ils créent un nouveau tableau au lieu de muter le tableau d'origine dans l'état. Je ferais quelque chose dans ces lignes.

Il est également recommandé de mettre en majuscule le nom du composant.

selectLocation = (id, type, lng, lat, polydata, name, clear = false) => {
        //console.log(type);
        //console.log(lng);
        //console.log(lat);
        //console.log(polydata);

        let selectedType = "selected" + type;
        let previousState = [];
        let updatedData = [];

        if (clear) {
          this.setState({
            selectedCountries: [],
            selectedLocations: [],
            selectedServices: [],
            selectedPoints: [],
            mapCenter: [lng, lat],
            locationGeoCoords: [polydata]
          });
        } else {
          const data = this.state[selectedType];
          if (data.indexOf(id) === -1) {
            //Push id
            updatedData = [...data, id];
          } else {
            updatedData = data.filter((value) => value !== id);
          }
        }

        if(type) {
          this.setState({
            [selectedType]: updatedData,
            refreshData: true
          });
        }
      };

      render() {
        return (
          <component
            selectedCountries={this.state.selectedCountries}
            selectedLocations={this.state.selectedLocations}
            refreshData={this.state.refreshData}
          />
        );
      }
    }
2
Sushanth --

vous êtes-vous assuré que les accessoires des emplacements et des pays changent réellement? Si oui, le code suivant devrait fonctionner:

componentDidUpdate(prevProps) {
  if (this.props.selectedCountries.length !== prevProps.selectedCountries.length) {
    console.log("updated selected countries");
  }

  if (this.props.selectedLocations.length !== prevProps.selectedLocations.length) {
    console.log("updated selected locations");
  }
}

J'ai créé un violon pour présenter l'effet ici: https://codesandbox.io/s/o580n8lnv5

0
grenzbotin