N'y a-t-il pas un moyen simple de transmettre un enfant props
à son parent à l'aide d'événements, dans React.js?
var Child = React.createClass({
render: function() {
<a onClick={this.props.onClick}>Click me</a>
}
});
var Parent = React.createClass({
onClick: function(event) {
// event.component.props ?why is this not available?
},
render: function() {
<Child onClick={this.onClick} />
}
});
Je sais que vous pouvez utiliser des composants contrôlés pour transmettre la valeur d'une entrée, mais ce serait bien de passer l'ensemble du kit n 'kaboodle. Parfois, le composant enfant contient un ensemble d'informations que vous préférez ne pas avoir à rechercher.
Peut-être existe-t-il un moyen de lier le composant à l'événement?
MISE À JOUR - 9/1/2015
Après avoir utilisé React pendant plus d'un an, et stimulé par la réponse de Sébastien Lorber, j'ai conclu que passer des composants enfants comme arguments aux fonctions chez les parents n'est pas en fait la manière React, ni une bonne idée. J'ai changé de réponse.
javascript
reactjs
KendallB
la source
la source
Réponses:
Modifier : voir les exemples finaux pour les exemples mis à jour ES6.
Cette réponse traite simplement le cas de la relation directe parent-enfant. Lorsque le parent et l'enfant ont potentiellement beaucoup d'intermédiaires, vérifiez cette réponse .
D'autres solutions ne sont pas pertinentes
Bien qu'ils fonctionnent toujours bien, il manque quelque chose de très important à d'autres réponses.
Le parent a déjà cet accessoire enfant! : si l'enfant a un accessoire, c'est parce que son parent a fourni cet accessoire à l'enfant! Pourquoi voulez-vous que l'enfant remette l'accessoire au parent, alors que le parent a évidemment déjà cet accessoire?
Meilleure mise en œuvre
Enfant : ça ne doit vraiment pas être plus compliqué que ça.
Parent avec enfant unique : en utilisant la valeur qu'il transmet à l'enfant
JsFiddle
Parent avec liste d'enfants : vous avez toujours tout ce dont vous avez besoin sur le parent et n'avez pas besoin de rendre l'enfant plus compliqué.
JsFiddle
Il est également possible d'utiliser
this.handleChildClick.bind(null,childIndex)
puis d'utiliserthis.state.childrenData[childIndex]
Notez que nous lions avec un
null
contexte car sinon React émet un avertissement lié à son système de liaison automatique. L'utilisation de null signifie que vous ne souhaitez pas modifier le contexte de la fonction. Voir également .À propos de l'encapsulation et du couplage dans d'autres réponses
C'est pour moi une mauvaise idée en terme de couplage et d'encapsulation:
Utilisation d'accessoires : Comme je l'ai expliqué ci-dessus, vous avez déjà les accessoires dans le parent, il est donc inutile de passer tout le composant enfant pour accéder aux accessoires.
Utilisation des références : vous avez déjà la cible de clic dans l'événement, et dans la plupart des cas, cela suffit. De plus, vous auriez pu utiliser une référence directement sur l'enfant:
Et accédez au nœud DOM dans le parent avec
Pour les cas plus avancés où vous souhaitez accéder à plusieurs références de l'enfant dans le parent, l'enfant peut passer tous les nœuds dom directement dans le rappel.
Le composant a une interface (accessoires) et le parent ne doit rien supposer du fonctionnement interne de l'enfant, y compris sa structure DOM interne ou les nœuds DOM pour lesquels il déclare des références. Un parent utilisant une référence d'un enfant signifie que vous couplez étroitement les 2 composants.
Pour illustrer le problème, je vais prendre cette citation sur le Shadow DOM , qui est utilisé dans les navigateurs pour rendre des choses comme des curseurs, des barres de défilement, des lecteurs vidéo ...:
Le problème est que si vous laissez les détails de l'implémentation enfant s'infiltrer dans le parent, il est très difficile de refactoriser l'enfant sans affecter le parent. Cela signifie qu'en tant qu'auteur de bibliothèque (ou en tant qu'éditeur de navigateur avec Shadow DOM), cela est très dangereux car vous laissez trop accès au client, ce qui rend très difficile la mise à niveau du code sans rompre la rétrocompatibilité.
Si Chrome avait implémenté sa barre de défilement permettant au client d'accéder aux nœuds dom internes de cette barre de défilement, cela signifie que le client peut avoir la possibilité de simplement casser cette barre de défilement, et que les applications se briseraient plus facilement lorsque Chrome effectuerait sa mise à jour automatique après la refactorisation du scrollbar ... Au lieu de cela, ils ne donnent accès qu'à certaines choses sûres comme la personnalisation de certaines parties de la scrollbar avec CSS.
À propos de l'utilisation d'autre chose
Passer le composant entier dans le rappel est dangereux et peut amener les développeurs novices à faire des choses très étranges comme appeler
childComponent.setState(...)
ouchildComponent.forceUpdate()
, ou lui assigner de nouvelles variables, à l'intérieur du parent, ce qui rend l'application beaucoup plus difficile à raisonner.Edit: exemples ES6
Comme de nombreuses personnes utilisent maintenant ES6, voici les mêmes exemples de syntaxe ES6
L'enfant peut être très simple:
Le parent peut être soit une classe (et il peut éventuellement gérer l'état lui-même, mais je le passe comme accessoire ici:
Mais il peut également être simplifié s'il n'a pas besoin de gérer l'état:
JsFiddle
AVERTISSEMENT PERF (s'applique à ES5 / ES6): si vous utilisez
PureComponent
oushouldComponentUpdate
, les implémentations ci-dessus ne seront pas optimisées par défaut car elles utilisentonClick={e => doSomething()}
ou se lient directement pendant la phase de rendu, car cela créera une nouvelle fonction à chaque rendu du parent. S'il s'agit d'un goulot d'étranglement dans votre application, vous pouvez transmettre les données aux enfants et les réinjecter dans un rappel "stable" (défini sur la classe parente et lié authis
constructeur de la classe) afin que l'PureComponent
optimisation puisse démarrer, ou vous peut implémenter le vôtreshouldComponentUpdate
et ignorer le rappel dans la vérification de comparaison des accessoires.Vous pouvez également utiliser la bibliothèque Recompose , qui fournit des composants d'ordre supérieur pour réaliser des optimisations affinées:
Dans ce cas, vous pouvez optimiser le composant enfant en utilisant:
la source
props
. Se mettre d'accord?How do I know which of my children was chosen among a group?
cela ne fait pas vraiment partie de la question d'origine, mais j'ai inclus la solution dans ma réponse. Contrairement à votre modification, je pense qu'il n'est pas nécessaire de modifier l'enfant du tout, même lorsqu'il s'agit d'une liste, comme vous pouvez l'utiliserbind
directement dans le parent.onClick={this.handleChildClick.bind(null,childData)}
vous avez mentionnée sur la liaison automatique Est-ce toujours applicable maintenant que React n'a pas été inclus dans le modèle de classe . J'ai lu beaucoup de choses mais cette partie m'embrouille toujours. J'utilise ES6class model
d'ailleurs, j'ai donc changénull
pourthis
et mon code semble toujours fonctionner. Comment traduiriez-vous cette partie de votre code dans un style ES6?Mise à jour (9/1/15): L'OP a fait de cette question un peu une cible mouvante. Il a été mis à jour à nouveau. Je me sens donc responsable de mettre à jour ma réponse.
Tout d'abord, une réponse à votre exemple fourni:
Oui, c'est possible.
Vous pouvez résoudre ce problème en mettant à jour Child's
onClick
pour qu'il soitthis.props.onClick.bind(null, this)
:Le gestionnaire d'événements de votre parent peut alors accéder au composant et à l'événement comme suit:
Instantané JSBin
Mais la question elle-même est trompeuse
Le parent connaît déjà celui de l'enfant
props
.Cela n'est pas clair dans l'exemple fourni, car aucun accessoire n'est réellement fourni. Cet exemple de code pourrait mieux prendre en charge la question posée:
Il devient beaucoup plus clair dans cet exemple que vous savez déjà quels sont les accessoires de Child.
Instantané JSBin
S'il s'agit vraiment d'utiliser les accessoires d'un enfant…
S'il s'agit vraiment d'utiliser les accessoires d'un enfant, vous pouvez éviter tout raccordement avec l'enfant.
JSX possède une API d' attributs de diffusion que j'utilise souvent sur des composants comme Child. Il prend tous les
props
et les applique à un composant. L'enfant ressemblerait à ceci:Vous permettant d'utiliser les valeurs directement dans le parent:
Instantané JSBin
Et aucune configuration supplémentaire n'est requise lorsque vous connectez des composants enfants supplémentaires
Instantané JSBin
Mais je suppose que ce n'est pas votre cas d'utilisation réel. Alors creusons plus loin…
Un exemple pratique robuste
Il est difficile de parler de la nature générique de l'exemple fourni. J'ai créé un composant qui démontre une utilisation pratique de la question ci-dessus, implémenté de manière très réactive :
Exemple de travail
DTServiceCalculator Repo DTServiceCalculator
Ce composant est un simple calculateur de service. Vous lui fournissez une liste de services (avec noms et prix) et il calculera un total des prix sélectionnés.
Les enfants sont parfaitement ignorants
ServiceItem
est le composant enfant dans cet exemple. Il n'a pas beaucoup d'opinions sur le monde extérieur. Il nécessite quelques accessoires , dont l'un est une fonction à appeler lorsque vous cliquez dessus.<div onClick={this.props.handleClick.bind(this.props.index)} />
Il ne fait rien d'autre que d'appeler le
handleClick
rappel fourni avec leindex
[ source fourni ] .Les parents sont des enfants
DTServicesCalculator
est le parent-composant est cet exemple. C'est aussi un enfant. Regardons.DTServiceCalculator
crée une liste de composants enfantsServiceItem
et leur fournit des accessoires [ source ]. C'est le composant parent deServiceItem
mais c'est le composant enfant du composant qui lui passe la liste. Il ne possède pas les données. Donc, il délègue à nouveau la gestion du composant à sa source de composant parent<ServiceItem chosen={chosen} index={i} key={id} price={price} name={name} onSelect={this.props.handleServiceItem} />
handleServiceItem
capture l'index, transmis par l'enfant, et le fournit à son parent [ source ]Les propriétaires savent tout
Le concept de «propriété» est important dans React. Je recommande d'en lire plus ici .
Dans l'exemple que j'ai montré, je continue de déléguer la gestion d'un événement dans l'arborescence des composants jusqu'à ce que nous arrivions au composant propriétaire de l'état.
Quand nous y arrivons enfin, nous gérons la sélection / désélection d'état comme ceci [ source ]:
Conclusion
Essayez de garder vos composants les plus extérieurs aussi opaques que possible. Efforcez-vous de vous assurer qu'ils ont très peu de préférences sur la façon dont un composant parent pourrait choisir de les implémenter.
Gardez à l'esprit qui détient les données que vous manipulez. Dans la plupart des cas, vous devrez déléguer la gestion des événements dans l'arborescence au composant propriétaire de cet état.
En plus: le modèle Flux est un bon moyen de réduire ce type de connexion nécessaire dans les applications.
la source
Parent
peut s'agir d'un tel Controller-View, alors qu'il neChild
s'agit que d'un dumb-View (composant). Seuls les Controller-Views doivent avoir connaissance de l'application. Dans ce cas, vous passeriez toujours l'action deParent
àChild
comme accessoire. En ce qui concerne l'action elle-même, Flux a un modèle fortement prescrit pour interagir entre les actions pour mettre à jour les vues. facebook.github.io/flux/docs/…onClick={this.onClick.bind(null, this.state.text)}
pas besoin de lier l'état car le parent a cela. si justeonClick={this.onClick}
fonctionnera. oùonClick = ()=>{const text = this.state.text;..}
en parentIl semble qu'il y ait une réponse simple. Considère ceci:
La clé appelle
bind(null, this)
l'this.props.onClick
événement, transmis par le parent. Maintenant, la fonction onClick accepte les argumentscomponent
, ETevent
. Je pense que c'est le meilleur de tous les mondes.MISE À JOUR: 9/1/2015
C'était une mauvaise idée: laisser les détails de l'implémentation enfant s'infiltrer dans le parent n'a jamais été un bon chemin. Voir la réponse de Sébastien Lorber.
la source
this
intérieur de la fonction (ce qui n'est pas nécessaire de toute façon), et le second est ajouté comme premier argument lorsque onClick est appelé.La question est de savoir comment passer l'argument de l'enfant au composant parent. Cet exemple est facile à utiliser et testé:
Regardez JSFIDDLE
la source
Fondamentalement, vous utilisez des accessoires pour envoyer des informations vers et depuis l'enfant et le parent.
Pour ajouter à toutes les merveilleuses réponses, permettez-moi de donner un exemple simple qui explique le passage des valeurs de l'enfant au composant parent dans React
App.js
Header.js
Main.js
C'est tout, vous pouvez maintenant transmettre des valeurs de votre client au serveur.
Jetez un œil à la fonction Change dans Header.js
Voici comment vous poussez des valeurs dans les accessoires du client vers le serveur
la source
Voici une implémentation ES6 simple en 3 étapes utilisant la liaison de fonction dans le constructeur parent. C'est la première façon que le didacticiel officiel de Reaper recommande (il y a aussi la syntaxe des champs de classe publique non couverte ici). Vous pouvez trouver toutes ces informations ici https://reactjs.org/docs/handling-events.html
Fonctions parentales pour que les enfants puissent les appeler (et transmettre les données au parent!: D)
Fonction parent
Constructeur parent
Prop transmis à l'enfant
Appel d'événement enfant
la source
Ceci est un exemple sans utiliser l'événement onClick. Je passe simplement une fonction de rappel à l'enfant par des accessoires. Avec ce rappel, l'appel enfant renvoie également des données. J'ai été inspiré par les exemples dans les documents .
Petit exemple (c'est dans un fichier tsx, donc les accessoires et les états doivent être déclarés complètement, j'ai supprimé une logique des composants, donc c'est moins de code).
* Mise à jour: l'important est de le lier au rappel, sinon le rappel a la portée de l'enfant et non du parent. Seul problème: c'est le "vieux" parent ...
SymptomChoser est le parent:
Le symptôme est l'enfant (dans les accessoires de l'enfant, j'ai déclaré la fonction de rappel, dans la fonction selectedSymptom, le rappel est appelé):
la source