React: componentDidReceiveProps S'il vous plaît

Créé le 27 févr. 2015  ·  94Commentaires  ·  Source: facebook/react

Je voudrais humblement demander un hook componentDidReceiveProps, souvent j'aimerais faire quelque chose à la fois sur componentWillMount et componentWillReceiveProps, mais parce que this.props n'a pas encore été défini, je suis obligé de passer des accessoires au lieu de lire directement à partir de this.props .

Avant le nouveau crochet

componentWillMount() {
  this.setup(this.props.id);
}

componentWillReceiveProps(next) {
  this.setup(next.id);
}

setup(id) {
  UserActions.load(id);
}

Après le nouveau crochet

componentWillMount() {
  this.setup();
}

componentDidReceiveProps() {
  this.setup();
}

setup() {
  UserActions.load(this.props.id);
}

Dans cet exemple simple, cela peut sembler une petite chose, mais souvent le passage des accessoires est profond et au lieu de référencer commodément this.props, on est obligé de sonder les accessoires dans tout le composant.

Veuillez envisager d'ajouter componentDidReceiveProps tant que crochet pour tirer parti du même code que celui utilisé dans componentWillMount sans forcer les deux à installer des accessoires dans tout le composant.

Commentaire le plus utile

@syranide Le problème, c'est lorsque la configuration doit appeler des méthodes qui ont également besoin d'accessoires, qui doivent appeler des méthodes qui ont également besoin d'accessoires...

Tous les 94 commentaires

Pourquoi pas setup(props) ?

En parcourant mes propres projets, je peux voir que j'ai fait cela là où j'avais des besoins similaires (un autre dérive un morceau d'état basé sur des accessoires), en passant simplement un ensemble d'accessoires différent en cas de besoin afin que vous n'ayez qu'à passer quelque chose de plus lors de la réutilisation, sans dupliquer la connaissance des accessoires nécessaires :

setup(props) {
  props = props || this.props
  UserActions.load(props.id)
}

@syranide Le problème, c'est lorsque la configuration doit appeler des méthodes qui ont également besoin d'accessoires, qui doivent appeler des méthodes qui ont également besoin d'accessoires...

+1 semble être un tas de câblage inutile dans l'application avec le modèle actuel. Cela pourrait être un moyen standardisé et concis de résoudre le problème. J'ai vu un groupe de personnes se brûler sur this.props à l'intérieur de ComponentWillReceiveProps, un signe clair que ce n'est pas intuitif.

+1, je trouve aussi cela frustrant.

Ne trouvez plus que ce soit un problème.

+1, je me retrouve aussi à beaucoup faire circuler des accessoires. Semblable à @insin ci-dessus, j'utilisais les paramètres par défaut pendant un certain temps :

setup(props = this.props) {
  doSomething(props);
}

Mais j'ai décidé que c'était un anti-modèle en raison des bugs subtils qu'il peut causer si vous oubliez de passer newProps.

+1

Je pense que la raison pour laquelle il n'est pas disponible est que this.props et this.state _always_ correspondent aux valeurs rendues. Il n'y a aucun moyen d'implémenter componentDidReceiveProps qui ne déclenche pas un autre rendu sans briser cette contrainte.

La plupart du temps, si vous utilisez componentWillReceiveProps , vous voulez en fait soit un composant d'ordre supérieur à la Relay , soit quelque chose comme le crochet observe proposé pour React 0.14 .

+1
De plus, vous pouvez implémenter componentDidReceiveProps sans modifier this.props ou this.state . Si tout ce que vous avez à faire est de lire à partir de ceux-ci, vous ne déclencherez pas un autre rendu. Si vous écrivez à des accessoires ou à un état dans cet appel de fonction proposé, alors vous vous tirez une balle dans le pied, mais c'est le même cas pour toutes les autres méthodes du cycle de vie.

+1

Je veux pouvoir répondre à l'événement new props lorsque shouldComponentUpdate renvoie false , donc dans mon cas, je ne peux pas utiliser componentDidUpdate .

+1

+1

Qu'en est-il de componentWillMount et componentWillUpdate @iammerrick

Je veux pouvoir répondre au nouvel événement props lorsque shouldComponentUpdate renvoie false, donc dans mon cas, je ne peux pas utiliser componentDidUpdate.

Utiliser componentWillReceiveProps ?

+1

+1 cela aide avec le code DRY et la logique simplifiante.

Je serais ouvert à ce que componentDidReceiveProps soit appelé lors de la configuration initiale pour que l'exemple démarrant ce fil ne soit qu'une seule fonction :

componentDidReceiveProps() {
  UserActions.load(this.props.id);
}

Les pensées?

componentWillReceiveProps() {
  setTimeout(()=> {
    if(this.isMounted()) {
      this.componentDidReceiveProps();
    }
  });
}
componentDidReceiveProps() {
  UserActions.load(this.props.id);
}

Qu'est-ce que tu penses?

@YourDeveloperFriend Je pense que cela dépend de son fonctionnement par rapport aux autres crochets de cycle de vie et des retards de rendu dus aux délais d'expiration en cascade sur les composants imbriqués.

Ces types de hooks de cycle de vie doivent être appelés de manière synchrone dans une passe qui est garantie d'être appelée avant le rendu. Je n'ai pas étudié la base de code de React, mais je suppose que le rendu n'est pas appelé sur un délai d'attente.

Très probablement, la meilleure solution consistera à enregistrer des crochets de pré-rendu ou à marquer les composants dont les accessoires ont été modifiés afin que la logique de rendu appelle componentDidReceiveProps avant d'appeler render.

+1 s'il vous plaît. Tellement moche.

Non, ça va. Il existe de meilleures solutions.

+1

componentDidReceiveProps() existe déjà : il s'appelle render() . Cependant, il peut y avoir un cas (comme dans l'exemple de @iammerrick ) où vous devez charger/déclencher/etc quelque chose avant d'effectuer un rendu. Cela signifie une et une seule chose : vous faites quelque chose de mal.

Quand tu fais des choses comme

setup(id) {
    UserActions.load(id);
}

vous introduisez l'état complet soit dans le composant, soit (bien pire) à l'extérieur. Pourquoi avez-vous besoin de load() données chaque fois qu'un composant reçoit des accessoires (ils ne sont même pas garantis d'être nouveaux ) ? Si vous faites du lazy-loading, la bonne méthode consiste à demander les données dans la méthode render() :

render() {
    var actions = UserActions.load(id);
    if (actions) // render
    else // show spinner or return null, etc.
}

UserActions.load = function(id) {
    if (data) return data;
    else // request the data, emit change on success
}

@robyoder , passer des arguments aux fonctions n'est pas moche. Cela peut sembler trop verbeux mais c'est naturel dans le langage de programmation que vous avez choisi. Détruire l'API en ajoutant une méthode de cycle de vie de rechange juste pour réduire la verbosité est vraiment moche.

Alors dis-moi, @me-andre, pourquoi avons-nous à la fois componentWillUpdate et componentWillReceiveProps ?

À mon avis, c'est parce qu'ils servent à des fins différentes et que les deux sont utiles. Tout comme ces deux ne sont pas identiques, render n'est pas le même que l'hypothétique componentDidReceiveProps car il est appelé pour des raisons autres que de nouveaux accessoires ; de plus, vous n'avez pas accès aux accessoires précédents.

L'avantage des props précédents est que vous n'auriez pas à charger des données à chaque fois ; cela peut être conditionnel en fonction des accessoires et s'ils ont changé.

De toute évidence, "[la laideur] est dans l'œil du spectateur", car l'ajout d'une méthode de cycle de vie appropriée me semble être une solution beaucoup plus propre.

Il y a peut-être une autre façon de voir ça...

Disons que les principaux objectifs ici sont :

(1) réduire l'erreur humaine - j'ai oublié de transmettre des paramètres ou d'utiliser à nouveau props = props || this.props
(2) pour réduire le code passe-partout sans valeur ajoutée - pourquoi écrire quelque chose inutilement
(3) pour réduire le fardeau cognitif d'essayer de décider quelles méthodes de cycle de vie utiliser - pourquoi dois-je penser à ce genre de chose, pourquoi dois-je continuer à utiliser des approches légèrement différentes selon ce que je ressens ce jour-là, etc.

Alors peut-être que l'espace de solution consiste à simplifier à la fois l'utilisation de React et de l'API React elle-même pour atteindre ces objectifs.

Si vous réfléchissez au problème avec ces objectifs à l'esprit, certaines méthodes de cycle de vie pourraient peut-être être fusionnées et si vous souhaitez savoir qu'il s'agit d'une initialisation ou d'une mise à jour, vous pouvez le dire par la signature / les arguments appelants. Par exemple : beforeRender(prevProps, prevState) ou update(prevProps, prevState) .

Personnellement, j'ai l'impression qu'il y a trop de méthodes de cycle de vie et si elles étaient appelées de manière plus cohérente (sans ou avec prevProps / prevState lors du passage initial et de la mise à jour), cela pourrait simplifier mon code et augmenter ma productivité. De plus, les noms des méthodes de cycle de vie sont assez longs (j'ai tendance à ne pas les copier/coller plutôt que de les taper) et il est difficile de se rappeler lequel existera / a existé, ce qui me fait penser qu'ils pourraient / devraient être simplifiés.

@robyoder , la réponse courte pour laquelle nous avons à la fois componentWillUpdate et componentDidReceiveProps est qu'il y a une énorme différence entre eux. Ils sont similaires bien sûr, mais principalement en étant préfixés par componentWill .

| | l'état a changé | composant n'a pas été mis à jour |
| --- | --- | --- |
| componentWillUpdate() | oui | non |
| componentWillReceiveProps() | non | oui |

Comme vous l'avez peut-être remarqué, il existe des points / conditions du cycle de vie où une méthode est appelée et l'autre non. C'est pourquoi nous avons 2 méthodes de cycle de vie distinctes.

Cependant, componentDidReceiveProps() tel qu'il a été décrit dans cette rubrique ne représente aucun état ou condition de composant et ne donne pas accès à quoi componentWillReceiveProps() ce componentWillReceiveProps() ne représente pas. Il ajoute juste un léger sucre syntaxique qui peut ou non sembler utile ou plus facile - il s'agit d'une préférence personnelle, pas d'une exigence technique . Et c'est exactement la raison pour laquelle il ne faut pas l'ajouter : c'est subjectif. Vous dites que passer des arguments est laid - mais vous avez également dit que "[la laideur] est dans l'œil du spectateur". Pour moi, il semble que vous ayez répondu vous-même.

@me-andre, vous me répondez peut-être (@kmalakoff) et @robyoder en même temps. Ou peut-être pas, mais j'en profite pour faire avancer la discussion...

Ce que je disais, c'est que peut-être penser au-dessus de l'API actuelle avec ces trois objectifs ci-dessus pourrait donner de nouvelles idées ou perspectives sur la façon dont on pourrait simplifier l'API pour les atteindre. Bien sûr, après avoir fait l'exercice, nous pourrions nous retrouver au même endroit.

Passons à l'exercice....

Supposons que ce sujet est suivi et +1-ed parce qu'il y a quelque chose d'important et disons que l'ajout de componentDidReceiveProps n'est pas une bonne idée car cela augmente la surface de l'API.

En gardant à l'esprit le tableau et les 3 objectifs que j'ai mis en avant, quelqu'un a-t-il des idées pour simplifier l'API et/ou un autre moyen de donner aux personnes de ce fil ce qu'elles souhaitent et de ne pas étendre l'API (peut-être même la réduire/la simplifier ) ?

@kmalakoff , les 3 points dont vous parlez sont liés à l'API uniquement dans la mesure où vous utilisez l'API lorsque vous les rencontrez. Ils ne sont pas causés par une mauvaise conception.

Le premier problème dont vous parlez est que les méthodes de cycle de vie prennent des arguments différents. Eh bien, c'est parfaitement naturel - ils servent à des fins différentes. componentWillReceiveProps prend des accessoires non pas parce que la lune était pleine lorsque cette méthode a été ajoutée - mais parce qu'il s'agit de recevoir des accessoires qui n'ont pas encore été affectés au composant. props sont transmis uniquement dans les méthodes où ils (peuvent) différer de this.props . Il s'agit en fait d'un indice, pas d'un problème.
Le problème n°3 est qu'il est difficile pour vous de décider quel rappel/approche utiliser. Eh bien, ce n'est pas vraiment un problème tant que les méthodes dont je parle ci-dessus n'ont pas la même signature. Une fois que vous avez à la fois state et this.state , props et this.props qui sont égaux (lire sans signification) dans la plupart des méthodes, alors vous êtes empêtré dans des options de rechange et alternatives.
Le problème n° 2 concerne le code passe-partout... eh bien, React est une bibliothèque mince - et c'est beau, facile et strict à cause de cela. Si vous voulez créer un wrapper qui simplifierait nos vies et réduirait la quantité de code que nous écrivons chaque jour, pourquoi ne pas le faire ? Publiez-le comme votre propre npm qui dépend de react et vous avez terminé.

Concernant "il y a trop de méthodes de cycle de vie" - pas encore et ne le sera jamais si vous arrêtez de demander de nouveaux rappels pour lesquels vous n'avez pas de besoin technique. Le besoin technique est lorsque vous implémentez un composant complexe et qu'au milieu du travail, vous comprenez qu'il n'y a absolument aucun moyen de le faire sans un hack laid. Il s'agit de "pour déclencher une méthode DOM délicate, j'ai besoin de quelque chose à appeler au moment où le composant fait X mais il n'y a pas une telle méthode et je ne peux pas en ajouter une, donc j'utilise setTimeout et j'espère qu'il n'atterrira pas plus tôt que nécessaire". Pas quand vous dites "oh, j'en ai marre d'écrire props = this.props".

Et encore une chose...
Dans une application React bien conçue, vous n'avez pas besoin de la plupart des méthodes dont nous parlons ou vous les utilisez très rarement. getInitialState , componentWillMount , componentWillUnmount suffisent 99% du temps. Dans mon projet actuel, qui est une application commerciale relativement importante, componentWillReceiveProps est utilisé deux fois dans toute l'application. Je ne l'utiliserais pas du tout, mais l'environnement (lire le navigateur) est imparfait - manipulant certaines choses "à état en soi" telles que scrollTop ou s'appuyant sur des calculs de mise en page pour les futurs render s nécessite une synchronisation manuelle entre les transitions props et les changements DOM. Cependant, dans la plupart des cas "normaux", vous n'avez tout simplement pas besoin de savoir quand la transition props se produit.

@me-andre sur la base de mon expérience de travail avec React, je pense qu'il est possible d'améliorer / simplifier l'API. Je ne suis pas le seul, c'est pourquoi ce problème a été soulevé en premier lieu et est en train d'être +1-ed.

Si je réponds en fournissant des commentaires sur votre analyse, je ne pense pas que cela fera vraiment avancer les choses (c'est pourquoi j'ai évité de le faire jusqu'à présent) car c'est un peu biaisé vers le statu quo et justifiant l'API actuelle, mais Je serais heureux de fournir des commentaires sur les solutions potentielles! Les personnes impliquées dans ce problème cherchent à explorer des idées d'amélioration et des modifications potentielles de l'API pour résoudre les problèmes soulevés par leur expérience avec React (comme je l'ai décrit ci-dessus).

Peut-être avez-vous raison de dire que la communauté devrait innover pour faire avancer l'API et peut-être la ramener dans le noyau ou peut-être que l'API actuelle est parfaite telle quelle, mais je pense que c'est une excellente occasion d'examiner à quoi pourrait ressembler le changement avec l'équipe React.

Peut-être que la raison pour laquelle vous avancez des arguments comme vous l'êtes est que nous ne sommes que des utilisateurs de la bibliothèque avec une compréhension moins approfondie de l'API actuelle et des décisions qui y sont associées. Peut-être pourriez-vous faire appel à d'autres membres de l'équipe React qui sont aussi expérimentés et bien informés que vous pour voir si nous obtenons une perspective différente et peut-être même proposer une excellente solution ou pour obtenir un consensus sur le fait que c'est aussi bon que possible ?

@kmalakoff , imaginez que React est un moteur et 4 roues. Maintenant, chaque fois que vous voulez aller quelque part, vous construisez le reste de la voiture et cela finit par devenir ennuyeux. Sinon, vous vous plaignez du besoin de vous souvenir des détails du moteur de bas niveau et de tourner les roues avant à la main ne semble pas la bonne façon.
Ce que je recommanderais, c'est soit d'obtenir un véhicule complet (un cadre à part entière), soit de construire les composants nécessaires de manière à pouvoir les réutiliser au fil du temps.
Ce que je vois dans ce fil, ce sont des utilisateurs de moteurs qui se plaignent que le moteur n'a pas de système hydraulique ni d'éclairage intérieur. Ce que je pense, c'est que nous obtiendrions une merde complète si nous ajoutions ces fonctionnalités là où elles n'appartiennent pas.
React n'est pas un framework : c'est plus un moteur de rendu alimenté par diff qui expose un système de composants puissant. Il a une API de bas niveau et minimaliste mais suffisamment puissante pour vous permettre de construire littéralement n'importe quoi dessus.
N'hésitez pas à me contacter par e-mail si vous pensez que j'ai besoin de clarifier quelque chose - je ne veux pas que ce fil devienne un tutoriel.

@me-andre Je crois que nous comprenons bien votre position et votre argumentation maintenant. Merci! Vous avez peut-être raison de dire que l'API est déjà aussi bonne qu'elle le sera, mais il est également possible qu'elle puisse être améliorée.

Quelqu'un peut-il plaider en faveur d'un changement d'API ? par exemple. fournir une analyse comparative de diverses options (ajouter un composantDidReceiveProps vs fusionner / simplifier les API vs aucun changement)

L'équipe React surveille le problème et nous en discutons en interne. En principe, je penche toujours vers l'élimination de la surface d'API, donc je me retrouve à pencher vers les arguments de @me-andre. Cependant, notre équipe se réfère parfois affectueusement à componentDidReceiveProps comme "la méthode de cycle de vie manquante", et il y a de sérieuses discussions sur son ajout potentiel. L'important est que nous permettions les meilleures pratiques sans catalyser les mauvaises pratiques.

Ce qui serait le plus utile pour nous (ou du moins pour moi), c'est d'avoir une solide compréhension de POURQUOI les gens veulent cette méthode de cycle de vie. Qu'essayez-vous de faire dans ce cycle de vie qui n'est pas suffisamment couvert par les autres méthodes de cycle de vie ? Pourquoi quelqu'un voudrait-il faire UserActions.load(id); dans componentDidReceiveProps au lieu de dans le rendu comme suggéré dans https://github.com/facebook/react/issues/3279#issuecomment -163875454 (je peux penser à une raison, mais je suis curieux de savoir quelles sont vos raisons) ? Existe-t-il des cas d'utilisation autres que le lancement d'un chargement de données basé sur des accessoires ?

@jimfb Je pense que componentDidReceiveProps est exactement ce dont j'ai besoin et que d'autres méthodes sont inappropriées, mais je peux me tromper. Je serai heureux d'expliquer mon cas d'utilisation.

J'ai un itinéraire dans mon react-router qui ressemble à ceci :

    <Route path="/profile/:username" component={ProfilePage} />

Je dois récupérer les données du profil à partir d'une source externe, et pour le faire correctement, je dois faire une requête HTTP dans la méthode componentDidMount .

Malheureusement, lorsque je navigue d'un profil à un autre, React Router n'appelle plus la méthode constructeur ou la méthode componentDidMount (bien sûr, cela pourrait être un bug mais je vais supposer que ce n'est pas pour l'instant) .

J'ai pensé à résoudre ce problème en utilisant le componentDidReceiveProps théorique. Malheureusement, il n'existe pas encore et componentWillReceiveProps ne répondra pas à mes besoins.

Tout pointeur à ce sujet serait grandement apprécié.

Mon intuition est que componentDidReceiveProps est exactement ce dont j'ai besoin.

@shea256 Pouvez-vous expliquer pourquoi componentWillReceiveProps ne répond pas à vos besoins ?

@shea256 Aussi, pourquoi votre composant doit-il faire une requête HTTP ? Que contient cette requête http ? S'il s'agit de données, pourquoi ne mettez-vous pas à jour votre composant de manière asynchrone lorsque le rappel de données revient ?

@jimfb Le cas courant pour moi est lorsque nous devons charger quelque chose de manière asynchrone en réponse à un changement de prop, ce qui implique de définir un état pour indiquer que le chargement est en cours, puis lorsque les données sont chargées, définir cet état.

Le montage et la réception de nouveaux accessoires devraient déclencher ce même cycle de chargement, donc componentDidMount et componentWillReceiveProps est l'endroit où appeler la fonction de mise à jour. render n'a pas d'informations sur s'il s'agit d'un nouvel accessoire, et de toute façon, setState de render est un non-non.

Donc, j'ai une fonction qui fait le chargement. Mais je dois passer en paramètre props et éviter soigneusement d'utiliser this.props qui sont obsolètes pour componentWillReceiveProps . Cela finit inévitablement par provoquer des bogues car vous devez vous rappeler d'utiliser les accessoires transmis ou vous obtenez de subtiles erreurs un-derrière lorsque des changements arrivent. Et les signatures de toutes les méthodes impliquées sont plus complexes car les accessoires doivent être transmis.

Oui, cela peut être fait avec l'API actuelle. Mais cela provoque un code plus maladroit et sujet aux erreurs, ce que React est si doué pour éviter en général.

@jimfb J'ai besoin d'obtenir le nouveau nom d'utilisateur dans le routeParam et avec componentWillReceiveProps je ne l'ai pas encore.

Je dois faire une requête HTTP afin de charger les données de profil à partir d'une source externe (les données ne sont pas stockées localement).

Et je peux mettre à jour mon composant dans la méthode de rendu mais ça me semble un peu sale :

constructor(props) {
  super(props)

  this.state = {
    id: this.props.routeParams.id,
    profile: {}
  }
}

componentDidMount() {
  this.getProfile(this.state.id)
}

render() {
  if (this.props.routeParams.id !== this.state.id) {
    this.getProfile(this.props.routeParams.id)
  }

  return (
    <div>
      <div className="name">
       {this.state.profile.name}
      </div>
    </div>
  )
}

@grassick a écrit :

Le cas courant pour moi est lorsque nous devons charger quelque chose de manière asynchrone en réponse à un changement de prop, ce qui implique de définir un état pour indiquer que le chargement est en cours, puis lorsque les données sont chargées, définir cet état.

Oui, c'est exactement mon cas d'utilisation.

Le montage et la réception de nouveaux accessoires doivent déclencher ce même cycle de chargement, donc componentDidMount et componentWillReceiveProps sont l'endroit où appeler la fonction de mise à jour.

Bien dit.

@shea256 ne peut-il pas être fait en utilisant componentWillReceiveProps place ?

constructor(props) {
  super(props)

  this.state = {
    id: this.props.routeParams.id,
    profile: {}
  }
}

componentDidMount() {
  this.getProfile(this.state.id)
}

componentWillReceiveProps(nextProps) {
  let { id } = nextProps.params
  if(id !== this.state.id) {
    this.getProfile(id, (profile) => {
      this.setState({ id: id, profile: profile })
    })
  }
}

render() {
  return (
    <div>
      <div className="name">
       {this.state.profile.name}
      </div>
    </div>
  )
}

@grassick a écrit :

Le cas courant pour moi est lorsque nous devons charger quelque chose de manière asynchrone en réponse à un changement de prop, ce qui implique de définir un état pour indiquer que le chargement est en cours, puis lorsque les données sont chargées, définir cet état.

@grassick a écrit :

render n'a pas d'informations sur s'il s'agit d'un nouvel accessoire, et de toute façon, setState de render est un non-non.

Juste en train de cracher ici : si componentDidUpdate était invoqué lors du rendu initial (en plus des rendus suivants), cela résoudrait-il votre cas d'utilisation ? Vous pouvez vérifier si les accessoires ont changé et charger toutes vos données dans componentDidUpdate , n'est-ce pas ? Et dans le rendu, vous sauriez que vous chargez des données si this.state.profileName != this.props.profileName . Cette alternative serait-elle suffisante pour vos cas d'utilisation ?


Existe-t-il des cas d'utilisation qui n'impliquent PAS le chargement de composants basés sur des accessoires ?

@calmdev hm, je crois que tu as raison. Je vais essayer ça.

@jimfb peut-être, même si j'ai essayé d'utiliser componentDidUpdate et j'ai pensé que cela ne fonctionnait pas. Je peux jeter un autre regard.

Et il semble que je puisse tout à fait vérifier this.state.profileName != this.props.profileName mais cela ressemble aussi à un hack, n'est-ce pas ? À ce stade, si componentWillReceiveProps(nextProps) finit par fonctionner, je préférerais simplement cela. Maintenant, ce qui me dérange, c'est le manque de symétrie avec componentDidMount . Puis-je utiliser componentWillMount au lieu de componentDidMount ?

J'ai juste l'impression que tout le cycle de vie pourrait être plus propre.

@shea256 , j'ai une question pour vous... avez-vous lu le README pour React ?
Je ne me sens pas à l'aise de dire cela, mais sinon, vous ne devriez peut-être pas demander de nouvelles fonctionnalités pour l'outil avec lequel vous n'êtes pas familier. Pour moi, cela semble même... absurde.
"Puis-je utiliser componentWillMount au lieu de componentDidMount ?"
Non, vous ne pouvez pas car, comme indiqué dans le fichier readme, componentWillMount est appelé avant que votre composant n'atteigne le DOM et componentDidMount - après cela. Eh bien, vous pouvez certainement remplacer une méthode par une autre et cela ne ferait que casser votre code. La raison pour laquelle nous avons ici 2 méthodes n'est pas esthétique (lire "symétrie"). C'est parce que nous pouvons avoir besoin d'une méthode pour faire une préparation avant le rendu et l'autre pour certaines requêtes / manipulations DOM initiales après le premier rendu. Mais même cela est exotique pour un composant React moyen. Normalement, vous n'avez simplement pas besoin d'accéder au DOM manuellement.
"Et il semble que je puisse tout à fait vérifier this.state.profileName != this.props.profileName mais cela ressemble aussi à un hack, n'est-ce pas ?"
Oui, toute votre approche est un hack. Et qui vous a dit que componentDidReceiveProps garantirait que les props ont été modifiés ? Rien ne le fera jamais à moins que vous ne définissiez shouldComponentUpdate .
C'est ainsi que fonctionne React.

@me-andre merci d'avoir sauté dessus mais tu es un peu trop abrasif à mon goût. De plus, je ne pense pas que vous ayez compris mes questions. Je connais assez bien ce que font componentWillMount et componentDidMount . J'attends la réponse de

@shea256 ,
« De plus, je ne pense pas que vous ayez compris mes questions.
Pourriez-vous s'il vous plaît indiquer où je manque le point lorsque je réponds à vos questions?
Aussi, pourriez-vous s'il vous plaît préciser ce que vous essayez de demander.
Aussi, nous ne sommes pas ici pour discuter de personnalités ou de goûts. Ce n'est pas une conversation privée, ni un support technique. Ce n'est même pas un site Web d'échange de piles où vous pourriez vous attendre à ce que l'on vous guide dans certains domaines de connaissances.
Je parle souvent lors de rencontres locales ainsi que de conférences internationales sur React (et pas seulement) et je suis très ouvert au partage de connaissances - quand et où cela est approprié. Vous pouvez toujours me contacter directement par e-mail ou skype.

Concernant votre problème de chargement des données de profil. Vous essayez de résoudre le problème de l'application d'une approche impérative classique à un framework orienté fonctionnel. Une vue dans React est une fonction des accessoires, de l'état et de l'environnement. Comme function(state, props) { return // whatever you've computed from it } (mais les choses deviennent légèrement plus complexes dans le monde réel - sinon React n'existerait pas du tout). Bien que dans 0.14 nous obtenions des composants fonctionnels purs, pour la plupart des composants, cette fonction d'entrée est render() .

Cela signifie que vous commencez à écrire à partir de render() et que vous supposez que vos accessoires sont toujours à jour et que vous ne vous souciez pas de savoir si props ont été modifiés ou non, combien de fois et où . Votre cas pourrait être mis en œuvre de la manière suivante :

// profile-view.js

var React = require('react');

module.exports = React.createClass({
    contextTypes: {
        app: React.PropTypes.object.isRequired
        // another option is var app = require('app')
        // or even var profiles = require('stores/profiles')
    },
    componentWillMount() {
        var {app} = this.context; // another option is to require('app')
        app.profiles.addListener('change', this.onStoreChange);
    },
    componentWillUnmount() {
        var {app} = this.context; // another option is to require('app')
        app.profiles.removeChangeListener('change', this.onStoreChange);
    },
    onStoreChange() {
        this.forceUpdate();
    },
    render() {
        var {app} = this.context;
        var profile = app.profiles.read(this.props.routeParams.id);
        if (profile) { // profile's been loaded
            return <div>{profile.name}</div>;
        } else { // not yet
            return <div>Loading...</div>;
        }
    }
});

// profiles-store.js
// app.profiles = new Profiles() on app initialization

var EventEmitter = require('events');
var {inherits} = require('util');

module.exports = Profiles;

function Profiles() {
    this.profiles = {};
}

inherits(Profiles, EventEmitter);

Profiles.prototype.read = function(id) {
    var profile = this.profiles[id];
    if (!profile) {
        $.get(`profiles/${id}`).then(profile => {
            this.profiles[id] = profile;
            this.emit('change');
        });
    }
    return profile;
};

Assez simple.
Et vous n'avez pas besoin de componentDidReceiveProps . Vous n'avez même pas besoin de componentWillReceiveProps et de crochets similaires. Si jamais vous sentez que vous en avez besoin pour un cas trivial, vous ne comprenez pas comment faire les choses dans React. Pour l'obtenir, veuillez utiliser les ressources appropriées, ne vous contentez pas de supprimer la section Problèmes du référentiel . C'est un peu trop abrasif à mon goût. On a même l'impression de ne pas respecter le temps des autres.

@me-andre Cela vaut probablement la peine d'atténuer un peu votre langage, car cela peut sembler un peu conflictuel même si vous essayez juste d'aider. Nous voulons créer une communauté accueillante pour tout le monde; nous étions tous des débutants à un moment donné. Même si vous avez raison sur certains de vos points sur l'API/la conception, le fait même que tant de personnes attribuent +1 au problème est une indication que quelque chose ne va pas, nous devrions donc essayer de comprendre ce que/pourquoi les gens veulent cela cycle de la vie. Peut-être que le problème est que nous ne communiquons pas suffisamment sur la façon d'écrire correctement les composants (documentation), ou peut-être que l'API de React a besoin d'un changement - de toute façon, cela vaut la peine de comprendre les plaintes/questions/commentaires ici.

@shea256 this.state.profileName != this.props.profileName vérifie si l'état interne (ce que le composant rend) correspond à ce que le parent demande au composant de rendre. C'est presque la définition de "le composant est mis à jour" ou "le composant est à jour", donc je ne le vois pas comme bidon. Au moins, pas plus bidon que l'idée de "lancer une demande de mise à jour des données lorsque le prop change et faire un setstate dans le rappel" est en premier lieu.

@shea256 Pour être clair : ce cycle de vie proposé ne vous permettrait pas de faire quelque chose que vous ne pourriez pas déjà faire aujourd'hui avec les cycles de vie actuels. Cela ne ferait que le rendre potentiellement plus pratique. Comme d'autres l'ont mentionné, ce que vous essayez de faire est possible avec les cycles de vie actuels (il existe plusieurs combinaisons de cycles de vie qui vous permettraient d'atteindre votre objectif). Si vous essayez de « le faire fonctionner », alors StackOverflow serait un meilleur endroit pour discuter. Ce problème github tente de comprendre le besoin de componentDidReceiveProps en ce qui concerne l'ergonomie des développeurs.

Et qui vous a dit que componentDidReceiveProps garantirait que les accessoires ont été modifiés ?

@me-andre a raison ici. La plupart des méthodes de cycle de vie ne garantissent pas réellement que quelque chose a changé ; ils indiquent seulement que quelque chose _pourrait_ avoir changé. Pour cette raison, vous devez toujours vérifier si previous === next si vous allez faire quelque chose comme faire une requête http. Un tas de personnes dans ce fil semblent faire l'hypothèse que leur valeur a changé simplement parce que la méthode du cycle de vie a été déclenchée.

@me-andre a écrit :

Vous essayez de résoudre le problème de l'application d'une approche impérative classique à un framework orienté fonctionnel.

Je pense que cela pourrait être la cause première du désir des gens de cette nouvelle méthode de cycle de vie, mais j'essaie toujours de comprendre pourquoi/comment les gens veulent utiliser cette méthode. Il est tout à fait possible que la sémantique actuelle du cycle de vie soit légèrement mal alignée avec ce que les gens veulent généralement faire.

Tous : existe-t-il des cas d'utilisation pour componentDidReceiveProps autres que "chargement de données de manière asynchrone en réponse à un changement d'accessoire" ?

cc @grassick @iammerrick

@jimfb J'ai recherché mon code et j'utilise également componentWillReceiveProps pour créer des objets coûteux à créer qui sont nécessaires pour le rendu. Ce cas souffre du même problème qu'il doit passer des accessoires et faire attention à ne pas utiliser this.props dans le code.

@jimfb a écrit :

@me-andre Cela vaut probablement la peine d'atténuer un peu votre langage, car cela peut sembler un peu conflictuel même si vous essayez juste d'aider. Nous voulons créer une communauté accueillante pour tout le monde; nous étions tous des débutants à un moment donné. Même si vous avez raison sur certains de vos points sur l'API/la conception, le fait même que tant de personnes attribuent +1 au problème est une indication que quelque chose ne va pas, nous devrions donc essayer de comprendre ce que/pourquoi les gens veulent cela cycle de la vie. Peut-être que le problème est que nous ne communiquons pas suffisamment sur la façon d'écrire correctement les composants (documentation), ou peut-être que l'API de React a besoin d'un changement - de toute façon, cela vaut la peine de comprendre les plaintes/questions/commentaires ici.

Merci d'avoir mentionné cela. Il est très important de vous assurer d'avoir une communauté accueillante et mes communications avec vous n'ont été qu'agréables.

@jimfb a écrit :

@shea256 this.state.profileName != this.props.profileName vérifie si l'état interne (ce que le composant rend) correspond à ce que le parent demande au composant de rendre. C'est presque la définition de "le composant est mis à jour" ou "le composant est à jour", donc je ne le vois pas comme bidon. Au moins, pas plus bidon que l'idée de "lancer une demande de mise à jour des données lorsque le prop change et faire un setstate dans le rappel" est en premier lieu.

Oui, cela semble raisonnable.

@jimfb a écrit :

@shea256 Pour être clair : ce cycle de vie proposé ne vous permettrait pas de faire quelque chose que vous ne pourriez pas déjà faire aujourd'hui avec les cycles de vie actuels. Cela ne ferait que le rendre potentiellement plus pratique. Comme d'autres l'ont mentionné, ce que vous essayez de faire est possible avec les cycles de vie actuels (il existe plusieurs combinaisons de cycles de vie qui vous permettraient d'atteindre votre objectif). Si vous essayez de « le faire fonctionner », alors StackOverflow serait un meilleur endroit pour discuter. Ce problème github tente de comprendre le besoin de componentDidReceiveProps en ce qui concerne l'ergonomie des développeurs.

Je suis tout à fait d'accord avec cela. Je n'ai pas posté mon cas d'utilisation particulier pour recevoir de l'aide à ce sujet. J'ai posté pour expliquer pourquoi je pensais que componentDidReceiveProps serait utile.

Moi et plus d'une douzaine d'autres personnes qui ont posté avaient clairement l'instinct d'utiliser quelque chose comme ça (ce qui signifie qu'il y en a probablement des centaines ou des milliers d'autres), ce qui m'indique que l'API n'est pas aussi intuitive qu'elle pourrait l'être.

@jimfb a écrit :

@me-andre a raison ici. La plupart des méthodes de cycle de vie ne garantissent pas réellement que quelque chose a changé ; ils indiquent seulement que quelque chose a pu changer. Pour cette raison, vous devez toujours vérifier si précédent === suivant si vous allez faire quelque chose comme faire une requête http. Un tas de personnes dans ce fil semblent faire l'hypothèse que leur valeur a changé simplement parce que la méthode du cycle de vie a été déclenchée.

Je ne fais pas cette hypothèse. J'ai omis le chèque mais j'en utilise maintenant un. Mais dans le pire des cas, une demande supplémentaire serait déclenchée.

@jimfb a écrit :

Je pense que cela pourrait être la cause première du désir des gens de cette nouvelle méthode de cycle de vie, mais j'essaie toujours de comprendre pourquoi/comment les gens veulent utiliser cette méthode. Il est tout à fait possible que la sémantique actuelle du cycle de vie soit légèrement mal alignée avec ce que les gens veulent généralement faire.

Peut-être. Je vais réfléchir plus à ça.

componentDidReceiveProps serait utile pour un cas d'utilisation spécifique que j'ai.

J'utilise l'architecture ReactRouter et Flux. Lorsque mon composant est instancié, je définis mon état sur un élément d'un magasin. Lorsque ce magasin émet un événement de modification, je mets à jour mon état à l'aide de la même requête de récupération.

Lorsque mes accessoires changent parce que j'ai navigué vers un autre ID d'article dans le même itinéraire, je dois interroger à nouveau mon magasin ou mon composant sera bloqué avec l'état de l'élément précédent dans le magasin.

Actuellement, lorsque componentWillReceiveProps est appelé, je vérifie si l'un de mes paramètres de route a changé, et si c'est le cas, j'appelle updateItemState. Mais, comme les props n'ont pas encore changé, je dois maintenant passer des props dans ma méthode.

this.updateItemState( nextProps );

updateItemState( props ) {
    props = props || this.props;

    this.setState( {
        item: this.getItemState( props )
    } );
}

getItemState( props ) {
    props = props || this.props;

    return this.ItemStore.get( props.params[ this.paramName ] );
}

deviendrait simplement

this.updateItemState();

updateItemState() {
    this.setState( {
        item: this.getItemState()
    } );
}

getItemState() {
    return this.ItemStore.get( this.props.params[ this.paramName ] );
}

Je pense que c'est un cas d'utilisation raisonnable.

@akinnee-gl et al : Si componentDidUpdate était déclenché après le montage initial en plus des mises à jour, cela résoudrait-il votre cas d'utilisation ?

@akinnee-gl , si vous utilisez Flux, vous n'avez pas besoin de définir l'état à partir d'un magasin. À moins que ce ne soit absolument impossible, vous devez maintenir l'état au même endroit. Quand il s'agit de Flux, cet endroit est le magasin lui-même. Lorsque le magasin émet du changement, vous venez de forceUpdate() puis dans render() vous read() votre magasin.

"Lorsque mes accessoires changent parce que j'ai navigué vers un autre ID d'article dans le même itinéraire, je dois interroger à nouveau mon magasin ou mon composant sera bloqué avec l'état de l'article précédent dans le magasin."

Jamais.

Jetez un œil : vous devez rendre un article particulier d'un magasin et quel article vous voulez rendre, vous décidez à partir de props . Si telle est votre exigence, elle doit être exprimée dans le code de la même manière que dans les mots :

    var item = this.props.store.read(this.props.id);
    return <div>{item.name}</div>;

Ceci est votre composant, rien de plus.
Afin de faire ce jeu avec Flux, vous pouvez écrire un composant réutilisable pour la liaison/déliaison du magasin :

<FluxWrapper store={store} component={Component} id={this.props.routeParams.id} />

var FluxWrapper = React.createClass({
    componentWillMount() {
        this.props.store.addListener('change', this.onStoreChange);
    },
    componentWillUnmount() {
        this.props.store.removeListener('change', this.onStoreChange);
    },
    onStoreChange() {
        this.forceUpdate();
    },
    render() {
        var Component = this.props.component;
        return <Component {...this.props} />;
    }
});

var Component = React.createClass({
    render() {
        var item = this.props.store.read(this.props.id);
        return <div>{item.name}</div>;
    }
});

Voyez à quel point vos composants peuvent devenir minuscules si vous utilisez correctement React.

Cependant, si vos magasins sont lourds et que vous ne pouvez pas simplement les read() tous les render() , alors vous avez besoin d'un middleware de mise en cache. Il peut s'agir d'un composant réutilisable (similaire à FluxWrapper ) ou d'un magasin proxy intermédiaire qui masque la méthode read() . Les magasins proxy sont simples et cool - ils peuvent non seulement mettre en cache les lectures, mais également supprimer les modifications si une modification du magasin parent n'était pas importante ou significative pour le cas.
C'est ce qu'on appelle la composition. Vous devriez préférer la composition à l'héritage ou à l'extension des fonctionnalités ou autre, car la composition évolue .
Dès que vous rencontrez un problème difficile à résoudre en utilisant un seul composant, veuillez envisager d'utiliser 2 composants ou plus au lieu d'introduire de la complexité dans les composants existants.

@jimfb , concernant mon ton : je ne suis pas anglophone et je n'ai même pas l'habitude de parler régulièrement, donc je peux parfois choisir les mauvais mots - je ne sens tout simplement pas comment ils sonnent émotionnellement.

Approche intéressante. Je le garderai à l'esprit. Tous les documents officiels de React disent de garder vos fonctions de rendu pures (ce qui signifie que vous ne devez accéder qu'aux accessoires et à l'état dans les méthodes de rendu). Tous les exemples Flux montrent l'état des paramètres du magasin.

@jimfb Le problème avec componentDidUpdate est qu'il est appelé pour une autre raison que le changement d'accessoires. De plus, il me faudrait attendre que le composant soit déjà mis à jour, puis appeler setState pour le mettre à jour à nouveau ! Semble assez inefficace.

@akinnee-gl componentWillReceiveProps peut également être appelé pour des raisons autres que le changement d'accessoires (voir : https://github.com/facebook/react/issues/3279#issuecomment-164713518), vous DEVEZ donc vérifier pour voir si l'accessoire a réellement changé de toute façon (quel que soit le cycle de vie que vous choisissez). De plus, si vous faites réellement des données asynchrones, vous allez attendre la prochaine boucle d'événement avant que votre rappel ne soit déclenché de toute façon, donc je ne pense pas que cela importerait si votre fonction était invoquée immédiatement avant/après votre fonction de rendu, non?

@jimfb Eh bien, si l'élément

@me-andre J'aime beaucoup votre approche consistant à simplement lire le magasin pendant le rendu. Cela semble simplifier le code. Je crains que vous perdiez un peu d'efficacité en faisant cela cependant. Vous perdez la possibilité de contrôler la mise à jour via shouldComponentUpdate, et cela vous oblige à ajouter le composant FluxWrapper supplémentaire que vous avez mentionné. Des idées là-dessus ?

J'ai suivi la discussion et j'aimerais revenir sur la troisième option : (1) l'API est excellente telle quelle, (2) elle a besoin de componentDidReceiveProps et (3) il existe peut-être une API plus simple.

Je considère le problème comme une opportunité de voir si nous pouvons résoudre le besoin sous-jacent soulevé par ce problème en réfléchissant à des changements plus profonds de l'API plutôt que de limiter la discussion à l'espace de solution de (1) et (2).

Une API simplifiée pourrait être basée sur les principes suivants :

(A) simplifier la structure du code / réduire le passe-partout
(B) garder les accessoires (entrées) séparés de l'état (interne)

La principale raison de (A) est que je me retrouve à écrire un texte passe-partout sans valeur ajoutée. Exemple:

componentWillMount() { this.actuallyCheckThePropsAndMaybeDoSomething(); }
componentWillReceiveProps(nextProps) { this.actuallyCheckThePropsAndMaybeDoSomething(nextProps); }

actuallyCheckThePropsAndMaybeDoSomething(props) {
  props = props || this.props;

  let relatedProps1 = _.pick(props, KEYS1);
  if (!shallowEqual(this.relatedProps1, relatedProps1) { // changed
   this.relatedProps1 = relatedProps1;

   // do something
  }

  let relatedProps2 = _.pick(props, KEYS2);
  if (!shallowEqual(this.relatedProps1, relatedProps2) { // changed
   this.relatedProps2 = relatedProps2;

   // do something else
  }
}

Je préférerais vraiment faire ce qui suit et ne pas avoir de chemin de code séparé pour la première fois par rapport à la modification :

propsUpdated(prevProps) {
  if (!shallowEqual(_.pick(prevProps || {}, KEYS1), _.pick(this.props, KEYS1)) { // changed
   // do something
  }

  if (!shallowEqual(_.pick(prevProps || {}, KEYS2), _.pick(this.props, KEYS2)) { // changed
   // do something
  }
}

En ce qui concerne (B), le principal problème avec le composantDidUpdate, comme il vient d'être mentionné, est que vous pouvez déclencher des appels de méthode répétés si vous définissez un état en raison de modifications de propriété, car il est appelé à la fois pour les accessoires (entrées) et pour l'état (interne). Ces chemins de code semblent être meilleurs lorsqu'ils sont découplés car les accessoires sont fournis de l'extérieur et l'état est défini à l'intérieur, par exemple. J'ai essayé / envisagé une quatrième possibilité de updated(prevProps, prevState) (un nom simplifié pour componentDidUpdate car moins de méthodes de cycle de vie pourraient permettre un nommage plus court) en utilisant componentDidUpdate pour réduire le passe-partout, mais je me trouve un peu insatisfait de la seconde redondante potentielle update et que la logique semble être assez indépendante dans la pratique.

En partant des principes de conception (je suis sûr qu'il y en a plus !), je me demande si quelque chose du genre propsUpdated et stateUpdated pourrait être une troisième option potentielle pour cette discussion ?

@kmalakoff Vous devrez toujours vérifier si les accessoires ont changé, car nous ne pourrons jamais vous dire définitivement que les accessoires ont / n'ont pas changé (car Javascript n'a pas de types de valeur et a une mutabilité).

Sur cette note, il pourrait peut-être appeler shouldComponentUpdate pour dire s'il doit appeler propsDidChange ou autre. Question distincte cependant.

@jimfb ne suit pas précisément la limitation de langue à laquelle vous faites référence et comment cela se rapporte à la simplification de l'API en général. Pouvez-vous s'il vous plaît expliquer un peu plus en détail ou avec un exemple? J'ai besoin de cette explication simplifiée/étoffée un peu pour comprendre...

Je pense qu'il veut dire qu'il n'y a pas de moyen intégré et rapide de vérifier si this.props === nextProps car ils peuvent ou non être deux objets distincts.

{ a: 1 } === { a: 1 } renvoie false car ce sont deux objets distincts, mais

var a = { a: 1 };
var b = a;
a === b

renvoie true car ils sont en fait tous les deux une référence au même objet.

Nous pourrions vérifier récursivement l'égalité de chaque propriété, mais cela pourrait être assez lent. C'est pourquoi c'est à nous de mettre en œuvre shouldComponentUpdate

@kmalakoff Je ne veux pas m'écarter de ce fil, mais voici un aperçu pour vous : https://gist.github.com/jimfb/9ef9b46741efbb949744

TLDR : @akinnee-gl a parfaitement raison dans son explication (merci !). Avec la correction mineure que nous ne pouvions pas toujours faire la vérification récursive de toute façon (même si nous le voulions, et les performances n'étaient pas un problème), car il n'y a aucun moyen de vérifier récursivement une fonction de rappel transmise en tant qu'accessoire.

Gardons ce fil sur le sujet cependant :P.

Merci à vous deux! Hmmm, toujours pas tout à fait clair sur pourquoi la simplification de l'API n'est pas une option pour résoudre ce problème. Je vais ajouter des commentaires à l' essentiel ...

Si quelqu'un souhaite participer à un plus large éventail de solutions, n'hésitez pas à nous rejoindre !

@jimfb @calmdev J'ai essayé vos suggestions et je comprends maintenant pourquoi componentDidReceiveProps n'ajoute rien de nouveau et ne devrait pas être ajouté en tant que fonction supplémentaire. Bien que j'aie fait confiance à votre parole plus tôt, il me semble maintenant logique pourquoi c'est le cas.

Pour illustrer comment je suis arrivé à cette réalisation, j'aimerais partager mon nouveau code. Peut-être que cela pourra aider les autres aussi.

Jetez un œil au composant de ma page de profil :

class ProfilePage extends Component {
  static propTypes = {
    fetchCurrentProfile: PropTypes.func.isRequired,
    currentProfile: PropTypes.object.isRequired
  }

  constructor(props) {
    super(props)
    this.state = { currentProfile: {} }
  }

  componentHasNewRouteParams(routeParams) {
    this.props.fetchCurrentProfile(routeParams.id)
  }

  componentWillMount() {
    this.componentHasNewRouteParams(this.props.routeParams)
  }

  componentWillReceiveProps(nextProps) {
    if (nextProps.routeParams.id !== this.props.routeParams.id) {
      this.componentHasNewRouteParams(nextProps.routeParams)
    }
    this.setState({
      currentProfile: nextProps.currentProfile
    })
  }

  render() {
    var profile = this.state.currentProfile
    return (
      <div>
        <h1>{ profile.name ? profile.name : null }</h1>
      </div>
    )
  }
}

Lorsque le composant est monté, il n'a pas de données de profil et doit charger le profil à partir d'une source externe.

Donc... Je l'ai appelé la fonction fetchCurrentProfile (enveloppée dans componentHasNewIdProp ) qui récupère les données de la source externe, puis envoie une action de mise à jour à Redux. Le réducteur reçoit cette action et met à jour l'état de l'application, qui met ensuite à jour les accessoires pour le composant ProfilePage .

Maintenant, puisque les accessoires ont été mis à jour, la fonction componentWillReceiveProps est appelée. Mais nous ne connaissons pas le contexte de l'événement de changement d'accessoire, nous devons donc déterminer quels accessoires (le cas échéant) ont été modifiés. Nous voyons que l'ID est le même, nous n'avons donc pas besoin d'appeler à nouveau fetchCurrentProfile . Ensuite, nous mettons à jour state.currentProfile afin que le composant sache effectuer un nouveau rendu avec les nouvelles données de profil (oui, je pourrais le faire avec des accessoires, mais il y a une autre raison à cela que je ne veux pas aborder ici). À ce stade, nous pourrions vérifier si props.currentProfile a changé avant de mettre à jour l'état, mais ce n'est pas une opération coûteuse, donc cela n'a pas d'importance si nous vérifions.

Alors... disons que nous voulons naviguer d'un profil à l'autre. Nous cliquons sur un lien et le routeur déclenche le changement de route. Nous avons maintenant de nouveaux paramètres de route et la fonction componentWillReceiveProps est déclenchée. Nous voyons que le id a changé et nous appelons donc à nouveau fetchCurrentProfile (via componentHasNewIdProp ).

Lorsque la nouvelle récupération revient et envoie l'action de redux, la prop currentProfile est à nouveau mise à jour, l'état est ensuite mis à jour et le composant est restitué avec la nouvelle vue.

Cet exemple illustre comment il doit y avoir un comportement différent lorsque le composant est monté et lorsque le composant reçoit de nouveaux accessoires. Il montre également comment les accessoires doivent être vérifiés pour les changements dans ce dernier cas et comment certaines fonctions doivent être appelées uniquement lors de certains changements d'accessoires.

Avec le recul, ce que je voulais essentiellement, c'était une fonction qui ne se mettait à jour que lorsque le routeParams changeait. Cependant, il n'est pas nécessaire d'ajouter une autre fonction car nous pouvons faire tout ce que nous voulons avec les fonctions existantes, et nous ne voulons pas compliquer le cycle de vie.

Quelque chose qui pourrait aider ici, cependant, est plus de documentation sur le cycle de vie, des exemples de travail, etc.

Merci pour votre aide les gars. S'il vous plaît laissez-moi savoir s'il y a quelque chose que j'ai mal ici. J'espère que cela sera utile à tous ceux qui tomberont sur ce fil à l'avenir.

@ shea256, votre exemple semble être un cas raisonnable pour ne pas avoir besoin d'une nouvelle API pour pouvoir réaliser ce dont vous avez besoin sans un nouveau point de vue API.

J'ai décrit plus de réflexions dans: https://gist.github.com/jimfb/9ef9b46741efbb949744 , mais j'ai toujours l'impression que nous devrions pouvoir rationaliser l'API pour écrire moins de code...

Imaginez que l'API vous permette d'écrire la même fonctionnalité, mais avec moins de passe-partout :

class ProfilePage extends Component {
  static propTypes = {
    fetchCurrentProfile: PropTypes.func.isRequired,
    currentProfile: PropTypes.object.isRequired
  }
  state = {currentProfile: {}}; // not material to example (babel-stage-1)

  // called both on init and update
  willReceiveProps(nextProps) {
    if (!this.props || (this.props.routeParams.id !== nextProps.routeParams.id)
      nextProps.fetchCurrentProfile(nextProps.routeParams.id)
  }

  render() {
    var profile = this.props.currentProfile;
    return (
      <div>
        <h1>{ profile.name ? profile.name : null }</h1>
      </div>
    )
  }
}

L'idée que j'espère sera prise en compte est de réduire la surface de l'API pour réduire le nombre de chemins de code et de passe-partout. Je me demande si la discussion s'ancre sur la demande initiale d'ajouter quelque chose alors que peut-être la regarder sous un angle différent ouvrirait de nouvelles voies.

Ce n'est qu'une option (ma préférence est receiveProps(prevProps) car idéalement, il n'y aurait qu'une seule méthode liée aux props où vous pourriez utiliser this.props), mais la partie importante est qu'il y a un chemin de code pour l'initialisation du composant et tout changement de prop plutôt que les différents chemins de code que nous avons maintenant avec différentes signatures d'API. Quelle que soit la solution, les gens s'entendent pour être meilleurs.

J'espère que ce problème permettra d'obtenir une réduction du passe-partout (pour clarifier mon besoin / problème !) et j'aimerais réfléchir un peu plus à ce à quoi cette solution pourrait ressembler (envisager de supprimer les API, méthodes de cycle de vie de manière significative, raccourcissant les noms de méthode maintenant que ES6 est largement disponible et que les composants semblent être la voie à suivre, etc.).

@akinnee-gl , avoir une application composée de nombreux composants minuscules est bien mieux que de quelques composants lourds pour plusieurs raisons :

  1. Cette approche rejoint le « principe de responsabilité unique »
  2. Vous pouvez clairement voir quel composant fait quoi
  3. Vous pouvez facilement composer des fonctionnalités et étendre des composants en enveloppant
  4. Les méthodes et les propriétés ne se heurtent pas
  5. Il est plus facile d'étendre une fonctionnalité car un composant encapsule une fonctionnalité

En ce qui concerne votre avis selon lequel la lecture à partir d'un magasin sur chaque rendu peut être inefficace, j'ai fait un résumé qui montre une idée de base sur la façon d'implémenter un composant middleware pour la mise en cache : https://gist.github.com/me-andre/0ca8b80239cd4624e6fc

J'ai fait une autre passe sur les principes / objectifs qui pourraient conduire à une API améliorée (espérons-le basée sur une méthode d'accessoires reçue comme suggéré dans ce numéro):

(A) simplifier la structure du code / réduire le passe-partout
(B) garder les accessoires (entrées) séparés de l'état (interne)
(C) permettre une méthode pour contrôler le rendu d'un composant
(D) simplifier la dénomination des méthodes en se basant sur l'hypothèse d'un sous-classement des composants
(E) réduire le nombre de méthodes props à une pour l'initialisation et les modifications
(F) la méthode props doit avoir this.props avec la dernière valeur

Il y a des éclaircissements sur certains d'entre eux dans l'essentiel.

@kmalakoff Conformément à l'essentiel, n'augmentons pas la portée de ces problèmes. Le problème est déjà suffisamment complexe, et faire une digression de la conversation dans une refonte complète de l'API ne sera pas traitable. Vous êtes invités à continuer à réfléchir à ces problèmes, mais veuillez garder ce fil sur le sujet.

@kmalakoff La plupart des points que vous mentionnez concernent d'autres problèmes. Par exemple (D) est répondu par https://github.com/reactjs/react-future/issues/40#issuecomment -142442124 et https://github.com/reactjs/react-future/issues/40#issuecomment - 153440651. Ce sont les fils appropriés pour avoir cette discussion. Si vous recherchez des discussions plus générales/holistiques sur la conception/l'API, le support approprié est probablement https://discuss.reactjs.org/

@jimfb J'y ai réfléchi après que vous ayez suggéré de déplacer cela vers l'essentiel et en fait, je ne crois pas que cette ligne d'analyse soit hors sujet ... la raison pour laquelle je m'intéresse à ce problème autour des accessoires reçus est que je pense avoir une méthode de cycle de vie des accessoires reçus me permettra de réduire le passe-partout.

S'il vous plaît, écoutez-moi... la réduction du passe-partout est le problème que la méthode du cycle de vie dans ce problème pourrait résoudre pour moi.

Je pense que cela pourrait également être une partie importante de la raison pour laquelle les gens s'intéressent à cette méthode de cycle de vie, car l'API actuelle encourage le passe-partout plus que nous ne le souhaiterions.

Cela dit, je serais heureux d'essayer de découpler les améliorations de l'API et, par exemple, de me concentrer uniquement sur l'exploration de l'espace de solution autour de l'amélioration de l'API liée aux accessoires dans ce problème.

@kmalakoff Le sujet du fil est défini par le titre et le premier message. Le titre est componentDidReceiveProps Please non lots of general ways to reduce boilerplate . Ce fil de discussion porte sur la réduction du passe-partout en particulier grâce à l'introduction d'une méthode de cycle de vie très spécifique. Cette discussion à elle seule est déjà suffisamment nuancée, sans introduire de sujets supplémentaires (comme renommer toutes les fonctions) qui sont déjà discutés dans d'autres numéros.

Vos points sont précieux, et je vous encourage à avoir la discussion, veuillez simplement la déplacer vers un autre fil, car nous voulons que les fils de discussion github se concentrent sur le sujet en cours. Sinon, les discussions sont trop difficiles à suivre/gérer. Il existe des fils de discussion pour la plupart des sujets que vous avez soulevés.

@jimfb pourquoi les gens demandent componentDidReceiveProps ? La raison pour laquelle je m'y intéresse est de réduire le passe-partout lié aux accessoires . Je ne sais pas comment énoncer cela plus clairement pour que je puisse être entendu et compris.

Vous avez demandé les problèmes et les cas d'utilisation, et j'ai déclaré cela comme le problème pour moi et j'ai montré un cas d'utilisation ci-dessus (répondant à @ shea256) qui semblent d'actualité, dans la portée et, de mon point de vue, important pour résoudre ce problème.

J'ai accepté de ne pas étendre le champ d'application aux problèmes/améliorations générales de l'API et à la volonté. Je promets! :clin d'œil:

Pour info : comme je l'ai dit précédemment, la raison pour laquelle j'ai commencé l'expérience de réflexion autour de ce problème était que les arguments semblaient un peu trop ciblés (par exemple, nous pouvons déjà faire tout ce dont nous avons besoin avec l'API actuelle) plutôt que d'identifier les motivations sous-jacentes du problème. Comme vous le savez, vous devez parfois prendre du recul, puis vous concentrer, puis voir sous un angle différent, puis revoir les hypothèses, enquêter sur les raisons sous-jacentes à la demande, etc. pour itérer vers la meilleure solution à un problème. J'espère avoir aidé à attirer l'attention sur cela et ma participation aidera à résoudre ce problème à notre satisfaction ! (bien sûr, j'espère également que l'API React évoluera pour être plus conviviale et poursuivra cette discussion ailleurs... merci pour les liens)

@kmalakoff , ok, pour réduire le passe-partout, vous créez simplement des classes ou des composants réutilisables à partir desquels vous sous-classez ou composez d'autres composants. Personne ne vous empêche de définir une méthode commune pour tous les composants de votre application. React offre une excellente extensibilité : vous pouvez définir des composants en tant qu'objets, fonctions ou classes. Vous pouvez étendre les composants par sous-classement, mixins ou usines.

@me-andre c'est absolument une option si ce problème ne conduit pas à une amélioration de l'API.

Cette question a été soulevée pour favoriser la discussion autour d'un désir d'apporter une modification à l'API pour l'améliorer. L'exploration d'alternatives dans le code client doit être définitivement envisagée, mais si des arguments solides sont avancés pour que l'API soit modifiée, ce type de solutions de contournement serait inutile. Afin de contrer les arguments, des arguments doivent également être présentés pour déterminer ce que devrait être une API améliorée, puis évalués par rapport à l'API actuelle pour les évaluer.

Par exemple, si vous deviez démontrer que l'API actuelle sans définir de superclasse personnalisée pourrait être utilisée de manière à réduire le passe-partout (par exemple, nous utilisons l'API de manière incorrecte, ou il existe des fonctionnalités dans l'API actuelle qui peuvent être utilisées pour atteindre un niveau similaire de réduction du passe-partout, etc.) ou prouver pourquoi il n'y a pas d'amélioration possible (par exemple, aucune solution générale n'existe car il existe un cas d'utilisation majeur qui ne pourrait pas être pris en charge dans nos options d'amélioration de l'API), etc., vous pourriez faire un cas où l'API est assez bonne telle quelle.

Si l'API exige que les utilisateurs écrivent des superclasses personnalisées pour les modèles de flux de contrôle de base et communs, cela renforce l'argument selon lequel il y a lieu d'améliorer l'API.

Curieux - pourquoi ne pas avoir déclenché componentWillReceiveProps avant le montage ? Si vous y réfléchissez, le composant reçoit vraiment des accessoires lorsqu'il est initialisé. Il ne reçoit tout simplement pas de nouveaux accessoires.

Quels sont les cas d'utilisation où vous voudriez déclencher quelque chose uniquement lors de la réception de nouveaux accessoires (et non lors de la réception initiale de l'accessoire) ?

Il se peut que je passe à côté d'une évidence, mais que j'essaie simplement de concilier les points de vue des différentes parties.

Dans tous les cas, si componentWillReceiveNewProps étaient importants dans certains cas, on pourrait toujours le simuler avec un componentWillReceiveProps modifié en effectuant une vérification sur les accessoires entrants.

@kmalakoff si componentWillReceiveProps déclenchait la première fois, cela répondrait-il à vos normes de simplification des API ?

componentWillReceiveProps ne pas être déclenché au montage n'est pas la raison pour laquelle les gens demandent componentDidReceiveProps . Les gens demandent componentDidReceiveProps parce qu'ils ont écrit toutes leurs méthodes pour accéder à this.props . Lorsque componentWillReceiveProps est appelé, les nextProps sont passés, mais this.props n'a pas encore changé, ce qui signifie que nous devons passer nextProps dans toutes les méthodes qui sont appelées en réponse à componentWillReceiveProps , au lieu de les laisser tels quels. Nous nous retrouvons avec une tonne de props = props || this.props et une tonne de passage de props dans chaque fonction que nous appelons.

@shea256 bons points. Le fait d'avoir des chemins de code différents pour l'initialisation par rapport aux modifications est l'une des causes premières du passe-partout des props. L'autre cause première est d'avoir des signatures différentes pour la gestion des accessoires comme le souligne @akinnee-gl.

C'est pourquoi j'essaie d'étendre l'espace de solution envisagé (par exemple, appeler également init) car il pourrait en fait y avoir une solution encore meilleure pour réduire davantage le passe-partout des props.

J'espère que nous pourrons aller plus loin :

Avant le nouveau crochet

componentWillMount() {
  this.setup(this.props.id);
}

componentWillReceiveProps(next) {
  this.setup(next.id);
}

setup(id) {
  UserActions.load(id);
}

Après le nouveau crochet (révisé)

componentDidReceiveProps(prevProps) {
  UserActions.load(this.props.id);
}

ou si UserActions.load ne peut pas vérifier l'identifiant actuellement chargé :

componentDidReceiveProps(prevProps) {
  if (!prevProps || (prevProps.id !== this.props.id))
    UserActions.load(this.props.id);
}

@kmalakoff , ce dont je parle, c'est que l'amélioration de l'API est absolument disponible pour vous dès maintenant : vous pouvez créer votre propre usine de composants, puis la partager avec nous (avec des exemples de cas d'utilisation). Cela rendra votre proposition et votre justification cent fois plus claires. Étant donné que tous les points du cycle de vie ont déjà des rappels appropriés, vous pouvez introduire n'importe quelle nouvelle méthode à n'importe quel point du cycle de vie/état de composant. Vous pouvez même mixer un émetteur d'événement dans votre composant et permettre d'attacher plusieurs gestionnaires pour un changement d'état.

@shea256 , une raison possible pour laquelle componentWillReceiveProps ne se déclenche pas avant le premier rendu est qu'il n'y a pas de this.props à ce moment-là. Ce que vous faites généralement dans componentWillReceiveProps est de comparer this.props[propName] avec newProps[propName] . Avoir la méthode déclenchée avant le premier rendu vous obligerait également à vérifier la présence de this.props . De plus, l'ensemble du composant est complètement non initialisé au moment où il reçoit props avant le rendu initial, il n'a même pas state .

@kmalakoff , j'ai publié deux fois des exemples de code qui montrent comment organiser un composant React de manière à ce qu'il n'ait pas besoin de setup ou de hacks similaires. Pourriez-vous s'il vous plaît expliquer pourquoi vous vous efforcez toujours de modifier le comportement d'un composant React au lieu d'ajuster votre code pour qu'il s'intègre à React ? Ce serait formidable si vous indiquiez simplement où mes échantillons sont inappropriés pour votre cas d'utilisation.

@akinnee-gl , la raison de ne pas introduire une nouvelle méthode pour accéder uniquement à this.props lors de la mise à jour est que nous avons une telle méthode - elle s'appelle render() . Il est même appelé après un chèque de shouldComponentUpdate() - qui est normalement un endroit où vous faites this.props !== newProps ou _.isEqual(this.props, newProps) etc.
Si vous pensez que vous devriez avoir une méthode distincte pour certaines configurations, pourquoi ne pas simplement sous-classer un composant React et définir une méthode render()

this.setup(this.props);
return this._render();

Je ne vois tout simplement pas en quoi cela simplifie les choses dans l'écosystème React, mais c'est ce que vous continuez à demander.

@me-andre la prémisse de ce problème n'est pas que nous ne pouvons pas réaliser ce que nous voulons avec l'API actuelle ni que nous ne pouvons pas contourner l'API actuelle dans le code client. La prémisse de ce problème est que l'API React actuelle est sous-optimale et doit être améliorée ; par exemple, si vous deviez proposer des principes sur ce à quoi ressemblerait une API optimale (comme j'ai essayé de le faire ci-dessus), l'API React actuelle obtiendrait un score moyen car elle est sous-optimale / déficiente dans un certain nombre de domaines.

Malheureusement, fournir des moyens dans le code client de contourner l'API React ne traite pas les causes profondes du problème, détourne le débat des problèmes sous-jacents et ne mènera pas à un débat sur les solutions potentielles pour améliorer l'API React.

En bref, j'ai déjà des solutions de contournement qui fonctionnent pour moi car j'ai un tas d'applications React en production, donc les meilleures pratiques pourraient être excellentes pour un article de blog, mais les utiliser comme sujet de débat dans ce numéro ne fera que nous détourner d'un véritable débat sur le véritable objectif de ce numéro : comment améliorer l'API React (dans ce numéro, limité aux cas d'utilisation des accessoires et du passe-partout).

React 1.0 doit viser le haut, pas le milieu. Une augmentation majeure de la version peut rompre la rétrocompatibilité, alors optons pour la meilleure API possible basée sur ce que nous avons appris de toutes ces années d'utilisation de la version 0.x.

(Pour info : je pense que les gens pourraient ne pas s'intéresser à vos exemples autant que vous l'espériez parce qu'ils ne viennent pas ici pour apprendre l'API actuelle, mais parce qu'ils recherchent / espèrent des améliorations à l'API, par exemple, ils pourrait être perçu comme ayant de bonnes intentions, mais étant légèrement désaligné)

Je pense que les gens pourraient ne pas s'intéresser à vos exemples autant que vous l'espérez parce qu'ils ne viennent pas ici pour apprendre l'API actuelle, mais parce qu'ils recherchent / espèrent des améliorations à l'API

D'accord, vous venez avec une proposition d'amélioration de l'API, mais vous montrez ensuite le code qui est bien trop éloigné des « bonnes pratiques de React ». Certaines choses ressemblent beaucoup aux pires pratiques. Alors vous dites : « c'est la raison d'un changement ». Oui, c'est la raison d'un changement mais pas dans la base de code React.
Je vous montre comment réorganiser le code pour qu'il fonctionne bien avec React, mais ignorez simplement la vitrine d'utilisation appropriée et continuez d'insister. Cela ne semble pas être un débat constructif.

Malheureusement, fournir des moyens dans le code client pour contourner l'API React ne résout pas les causes profondes du problème

Lorsque vous enveloppez une API de bas niveau avec une API de niveau supérieur, ce n'est pas une solution de contournement, mais une pratique courante. De nombreux frameworks brillants suivent cette idée.
Ce que je n'arrête pas de dire, c'est d'envelopper l'API moche existante avec ce que vous aimeriez utiliser et partager avec nous. Avec les exemples d'utilisation et les explications sur les raisons pour lesquelles cela s'est amélioré, ce serait incroyable.
Encore une fois, je ne vois pas de raison pour laquelle tu ne fais pas ça. Parce que si ce dont vous parlez est un problème commun, ce serait d'une grande aide pour beaucoup de gens.

J'ai un tas d'applications React en production, donc les meilleures pratiques pourraient être excellentes pour un article de blog, mais les utiliser comme axe de débat dans ce numéro ne fera que nous détourner d'un vrai débat

Ce que vous faites généralement lorsque vous construisez/concevez une API, c'est de prédire les problèmes, d'émettre des hypothèses sur des cas d'utilisation, etc. La raison pour laquelle les gens émettent des hypothèses n'est pas qu'ils essaient de s'abstraire d'un monde réel à la recherche de l'idéal. C'est juste un manque d'expérience - vous ne pouvez pas acquérir de l'expérience "à l'avance".

Vous dites que vous avez cette expérience, que vous avez vu de vrais problèmes et que vous avez des solutions de contournement que vous pouvez partager. C'est exactement ce qui peut rendre ce débat « réel » et « efficace ». Le React lui-même a été construit sur de vrais problèmes et défis - c'est pourquoi il résout de vrais problèmes d'architecture et pas seulement "comment écrire bonjour le monde en 3 lignes".

@me-andre je vous entends et votre argumentation est claire.

Vous avez raison de dire que le cœur de mon argument est que si nous établissons de meilleurs principes basés sur nos expériences collectives d'utilisation de l'API React actuelle et ouvrons le débat pour inclure des solutions non dogmatiques qui peuvent changer l'API de certaines manières fondamentales, nous pouvons et devrions saisissez l'opportunité d'améliorer l'API React pour la rendre encore meilleure qu'elle ne l'est aujourd'hui. Ne nous reposons pas sur nos lauriers quand il y a de la place pour s'améliorer !

Comment évalueriez-vous l'API React actuelle autour des accessoires ? (disons en utilisant des notes alphabétiques : F à A+), pourquoi, et que feriez-vous pour l'améliorer s'il est inférieur à A+ ?

@me-andre as-tu eu la chance de préparer ton classement et analyse ? J'aimerais savoir ce que vous pensez être les forces, les faiblesses et les opportunités de l'API actuelle.

+1

+1 S'il vous plaît

Y at-il un travail autour? J'ai besoin de ComponentDidReceiveProps

J'ai créé ce problème il y a plus d'un an et j'utilise React quotidiennement depuis. Je ne pense plus qu'il existe un cas d'utilisation pour componentDidReceiveProps qui justifie l'augmentation de l'API.

@AlexCppns qu'essayez -vous de faire ?

@iammerrick , en fait ça va, j'ai juste mal compris comment componentWillReceiveProps est utilisé.

J'ai rencontré cela plusieurs fois, et ce que j'ai fini par faire était:

componentWillReceiveProps(nextProps) {
  if (this.props.foo !== nextProps.foo) this.needsUpdate = true;
}
componentDidUpdate() {
  if (this.needsUpdate) {
    this.needsUpdate = false;
    // update the dom
  }
}

Ce n'est pas si mal.

@brigand , il n'y a pas besoin d'un drapeau - vous pouvez comparer les accessoires dans componentDidUpdate() :

componentDidUpdate(prevProps) {
    let needsUpdate = prevProps.foo !== this.props.foo;
    // ...whatever
}

De plus, votre solution pourrait être facilement cassée par shouldComponentUpdate() , ce qui peut empêcher le nouveau rendu.

Ah cool, merci !

@jimfb Je pense avoir un cas d'utilisation synchrone ci-dessous. Je pense qu'un componetDidReceiveProps aurait été parfait pour ça.

  componentDidMount() {
    this._selectAll()
  }

  componentDidUpdate(prevProps) {
    let shouldUpdateSelected = (prevProps.recordTypeFilter !== this.props.recordTypeFilter) ||
      (prevProps.statusFilter !== this.props.statusFilter) ||
      (prevProps.list !== this.props.list)

    if (shouldUpdateSelected) { this._selectAll() }
  }

  _selectAll() {
    this.setState({ selectedIds: this._getFilteredOrders().map((order) => ( order.id )) })
  }

  _getFilteredOrders() {
    let filteredOrders = this.props.list

    // recordTypeFilter
    let recordTypeFilter = this.props.recordTypeFilter
    filteredOrders = _.filter(filteredOrders, (order) => {
        // somelogic
    })

    // statusFilter
    let statusFilter = this.props.statusFilter
    filteredOrders = _.filter(filteredOrders, (order) => {
        // somelogic
    })

    return filteredOrders
  }

@chanakasan , votre exemple manque render() méthode
Deuxièmement, votre code est connecté à une logique métier personnalisée et n'est pas facile à lire. N'hésitez pas à expliquer, ne vous contentez pas de faire un copier-coller dans les autres.
J'ai cependant lu votre exemple et j'aimerais partager les réflexions suivantes :

  1. C'est le cas d'utilisation de componentWillReceiveProps , pas de componentDidUpdate . Si vous passez à componentWillReceiveProps , votre composant s'affichera à nouveau deux fois moins tout en conservant la même logique. Après un an depuis que j'ai quitté cette discussion, je ne vois toujours aucun cas d'utilisation pour componentDidUpdate sauf pour réagir aux modifications du DOM.
  2. Beaucoup mieux, cependant, serait d'éviter les hooks et de déplacer toute la logique vers la méthode render() / migrer vers un composant sans état, car this.state.selectedIds n'est pas réellement un état. C'est purement calculé à partir d'accessoires.

Salut @me-andre, Merci d'avoir pris le temps de répondre. J'ai lu la discussion sur cette page et je tiens à vous remercier d'y avoir participé.

Oui, un componentDidReceiveProps n'est pas nécessaire, mais les choses semblent mystérieuses sans lui.
Vous avez dit your component would re-render twice as less si j'utilise componentWillReceiveProps . C'est encore un mystère pour moi.

J'ai réfléchi et essayé les deux choses que vous avez suggérées auparavant, mais j'ai échoué.

  1. componentWillReceiveProps ne fonctionnera pas car la fonction _getFilteredOrders() appelée depuis _selectAll() besoin des newProps.
  2. Je ne pouvais pas penser à un moyen de dériver le selectedIds sans le stocker dans l'état.

Je viens de créer un exemple complet à partir de mon cas d'utilisation. Je l'ai rendu facile à comprendre autant que possible.

Si vous pouviez jeter un œil et m'orienter dans la bonne direction. Si je suis capable de comprendre cela correctement, je partagerai cet exemple dans un article de blog pour aider les autres également.

@chanakasan , allez, ça ressemble à un code de production. Je ne vais pas tout lire et vous aider gratuitement dans votre projet.

Cependant, je peux vous indiquer la bonne direction :

  1. componentWillReceiveProps() et componentDidUpdate() peuvent accéder aux props prev et next. Cela ressort clairement des documents officiels de React.
  2. À partir du copier-coller complet de votre code, il est maintenant évident que vous utilisez l'état pour stocker les identifiants sélectionnés qu'un utilisateur peut basculer. C'est bien d'utiliser l'état alors, mais toujours componentWillReceiveProps() déclencherait le re-rendu deux fois moins. (parce qu'un rendu se produira après componentWillReceiveProps() toute façon, setState() mettrait simplement à jour l'état pour le rendu à venir).
  3. S'il vous plaît jeter un oeil à la doc . Gagnez du temps et respectez les autres.

@me-andre Je pense avoir compris votre argument à propos de componentWillReceiveProps utilisant cette ligne dans la documentation :

componentWillReceiveProps() n'est pas invoqué si vous appelez simplement this.setState()

Mais l'inconvénient d'utiliser componentWillReceiveProps est que je devrai transmettre nextProps aux fonctions.

Je vais essayer de suivre vos conseils. Merci j'apprécie.

Au fait, je n'avais pas l'intention que vous m'aidiez gratuitement à mon projet de production :). C'est un exemple plus complet de mon exemple court précédent pour remplir tous les blancs concernant mon cas d'utilisation.

et si nous l'utilisions en conjonction avec shouldComponentUpdate ?
où nous ne souhaitons pas mettre à jour l'état du composant ou restituer,
mais nous avons besoin que this.props utilise les derniers accessoires pour effectuer un travail de script manuel après la réception des accessoires

mon travail consiste à définir this.props sur les nouveaux accessoires avant d'exécuter la fonction souhaitée

Ce serait vraiment bien d'avoir le ComponentDidMount ou un crochet pour cela. Pourquoi? Parce que, parfois, nous devons faire d'autres calculs qui ne dépendent pas du cycle de vie de React.

Par exemple : j'ai un composant parent qui peut être redimensionné. Le composant enfant est chargé de restituer une carte OpenLayer qui a une fonction chargée de redimensionner la carte. Cependant, cela devrait se produire une fois que l'enfant a obtenu les accessoires du parent et a également effectué d'autres calculs dans le cycle de vie de React.

Cette page vous a été utile?
0 / 5 - 0 notes