Passez les accessoires au composant parent dans React.js

295

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.

KendallB
la source
Il existe différentes réponses à des problèmes similaires ( ici et ici ), mais aucune ne semble particulièrement élégante
Bojangles
Je suis d'accord - passer des événements en amont est génial, mais ce serait génial de savoir avec certitude quel composant a provoqué l'événement.
KendallB
Veuillez regarder mes réponses, car je pense que la réponse acceptée n'est pas assez bonne; stackoverflow.com/a/31756470/82609
Sebastien Lorber
1
kit n 'kaboodle - Pour obtenir tout inclus. Pour obtenir toutes les cloches et les sifflets. La combonation. urbandictionary.com/define.php?term=kit%20and%20caboodle
Filip Bartuzi

Réponses:

268

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.

N'y a-t-il pas un moyen simple de transmettre les accessoires d'un enfant à son parent à l'aide d'événements, dans React.js?

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.

var Child = React.createClass({
  render: function () {
    return <button onClick={this.props.onClick}>{this.props.text}</button>;
  },
});

Parent avec enfant unique : en utilisant la valeur qu'il transmet à l'enfant

var Parent = React.createClass({
  getInitialState: function() {
     return {childText: "Click me! (parent prop)"};
  },
  render: function () {
    return (
      <Child onClick={this.handleChildClick} text={this.state.childText}/>
    );
  },
  handleChildClick: function(event) {
     // You can access the prop you pass to the children 
     // because you already have it! 
     // Here you have it in state but it could also be
     //  in props, coming from another parent.
     alert("The Child button text is: " + this.state.childText);
     // You can also access the target of the click here 
     // if you want to do some magic stuff
     alert("The Child HTML is: " + event.target.outerHTML);
  }
});

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é.

var Parent = React.createClass({
  getInitialState: function() {
     return {childrenData: [
         {childText: "Click me 1!", childNumber: 1},
         {childText: "Click me 2!", childNumber: 2}
     ]};
  },
  render: function () {
    var children = this.state.childrenData.map(function(childData,childIndex) {
        return <Child onClick={this.handleChildClick.bind(null,childData)} text={childData.childText}/>;
    }.bind(this));
    return <div>{children}</div>;
  },

  handleChildClick: function(childData,event) {
     alert("The Child button data is: " + childData.childText + " - " + childData.childNumber);
     alert("The Child HTML is: " + event.target.outerHTML);
  }
});

JsFiddle

Il est également possible d'utiliser this.handleChildClick.bind(null,childIndex)puis d'utiliserthis.state.childrenData[childIndex]

Notez que nous lions avec un nullcontexte 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:

var Parent = React.createClass({
  handleClick: function(childComponent) {
     // using childComponent.props
     // using childComponent.refs.button
     // or anything else using childComponent
  },
  render: function() {
    <Child onClick={this.handleClick} />
  }
});

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:

<Child ref="theChild" .../>

Et accédez au nœud DOM dans le parent avec

React.findDOMNode(this.refs.theChild)

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 ...:

Ils ont créé une frontière entre ce que vous, le développeur Web pouvez atteindre et ce qui est considéré comme des détails d'implémentation, donc inaccessible pour vous. Le navigateur peut cependant traverser cette frontière à volonté. Avec cette limite en place, ils ont pu créer tous les éléments HTML en utilisant les mêmes bonnes technologies Web, à partir des divs et des étendues comme vous le feriez.

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(...)ou childComponent.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:

const Child = ({
  onClick, 
  text
}) => (
  <button onClick={onClick}>
    {text}
  </button>
)

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:

class Parent1 extends React.Component {
  handleChildClick(childData,event) {
     alert("The Child button data is: " + childData.childText + " - " + childData.childNumber);
     alert("The Child HTML is: " + event.target.outerHTML);
  }
  render() {
    return (
      <div>
        {this.props.childrenData.map(child => (
          <Child
            key={child.childNumber}
            text={child.childText} 
            onClick={e => this.handleChildClick(child,e)}
          />
        ))}
      </div>
    );
  }
}

Mais il peut également être simplifié s'il n'a pas besoin de gérer l'état:

const Parent2 = ({childrenData}) => (
  <div>
     {childrenData.map(child => (
       <Child
         key={child.childNumber}
         text={child.childText} 
         onClick={e => {
            alert("The Child button data is: " + child.childText + " - " + child.childNumber);
                    alert("The Child HTML is: " + e.target.outerHTML);
         }}
       />
     ))}
  </div>
)

JsFiddle


AVERTISSEMENT PERF (s'applique à ES5 / ES6): si vous utilisez PureComponentou shouldComponentUpdate, les implémentations ci-dessus ne seront pas optimisées par défaut car elles utilisent onClick={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é au thisconstructeur de la classe) afin que l' PureComponentoptimisation 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:

// A component that is expensive to render
const ExpensiveComponent = ({ propA, propB }) => {...}

// Optimized version of same component, using shallow comparison of props
// Same effect as React's PureRenderMixin
const OptimizedComponent = pure(ExpensiveComponent)

// Even more optimized: only updates if specific prop keys have changed
const HyperOptimizedComponent = onlyUpdateForKeys(['propA', 'propB'])(ExpensiveComponent)

Dans ce cas, vous pouvez optimiser le composant enfant en utilisant:

const OptimizedChild = onlyUpdateForKeys(['text'])(Child)
Sébastien Lorber
la source
1
Oui, après avoir passé l'année dernière à utiliser React, je suis d'accord - il n'y a aucune bonne raison de passer des composants instanciés via des fonctions. Je vais déprécier ma propre réponse. Je suis également prêt à changer la réponse, avec peut-être quelques modifications: votre «meilleure mise en œuvre» ne répond pas à la raison réelle de cette question, qui est: «Comment savoir lequel de mes enfants a été choisi dans un groupe? Flux est la réponse pour toute application de taille décente, cependant, dans les petites applications, il est agréable de transmettre des valeurs (pas des composants) pour sauvegarder la chaîne d'appel via une fonction props. Se mettre d'accord?
KendallB
@KendallB heureux que vous soyez d'accord avec ma réponse :) 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'utiliser binddirectement dans le parent.
Sebastien Lorber
J'ai apporté une modification à votre réponse, la partie sur les références. omerwazir.com/posts/react-getdomnode-replaced-with-findDOMNode
ffxsam
Salut @SebastienLorber Je viens du futur. Concernant cette ligne que 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 ES6 class modeld'ailleurs, j'ai donc changé nullpour thiset mon code semble toujours fonctionner. Comment traduiriez-vous cette partie de votre code dans un style ES6?
JohnnyQ
J'ai aussi du mal à faire fonctionner cela dans le dernier React, qu'est-ce qui doit changer?
Hussein Duvigneau
143

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 onClickpour qu'il soit this.props.onClick.bind(null, this):

var Child = React.createClass({
  render: function () {
    return <a onClick={this.props.onClick.bind(null, this)}>Click me</a>;
  }
});

Le gestionnaire d'événements de votre parent peut alors accéder au composant et à l'événement comme suit:

  onClick: function (component, event) {
    // console.log(component, event);
  },

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:

var Child = React.createClass({
  render: function () {
    return <a onClick={this.props.onClick}> {this.props.text} </a>;
  }
});

var Parent = React.createClass({
  getInitialState: function () {
    return { text: "Click here" };
  },
  onClick: function (event) {
    // event.component.props ?why is this not available? 
  },
  render: function() {
    return <Child onClick={this.onClick} text={this.state.text} />;
  }
});

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 propset les applique à un composant. L'enfant ressemblerait à ceci:

var Child = React.createClass({
  render: function () {
    return <a {...this.props}> {this.props.text} </a>;
  }
});

Vous permettant d'utiliser les valeurs directement dans le parent:

var Parent = React.createClass({
  getInitialState: function () {
    return { text: "Click here" };
  },
  onClick: function (text) {
    alert(text);
  },
  render: function() {
    return <Child onClick={this.onClick.bind(null, this.state.text)} text={this.state.text} />;
  }
});

Instantané JSBin


Et aucune configuration supplémentaire n'est requise lorsque vous connectez des composants enfants supplémentaires

var Parent = React.createClass({
  getInitialState: function () {
    return {
      text: "Click here",
      text2: "No, Click here",
    };
  },
  onClick: function (text) {
    alert(text);
  },
  render: function() {
    return <div>
      <Child onClick={this.onClick.bind(null, this.state.text)} text={this.state.text} />
      <Child onClick={this.onClick.bind(null, this.state.text2)} text={this.state.text2} />
    </div>;
  }
});

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

ServiceItemest 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 handleClickrappel fourni avec le index[ source fourni ] .

Les parents sont des enfants

DTServicesCalculatorest le parent-composant est cet exemple. C'est aussi un enfant. Regardons.

DTServiceCalculatorcrée une liste de composants enfants ServiceItemet leur fournit des accessoires [ source ]. C'est le composant parent de ServiceItemmais 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} />

handleServiceItemcapture l'index, transmis par l'enfant, et le fournit à son parent [ source ]

handleServiceClick (index) {
  this.props.onSelect(index);
}

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 ]:

handleSelect (index) {
  let services = […this.state.services];
  services[index].chosen = (services[index].chosen) ? false : true;
  this.setState({ services: services });
}


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.

chantastic
la source
Merci pour la réponse concise, cela m'a vraiment aidé à mieux comprendre React! J'ai une question dans le même sens. J'utilise Flux pour pub / sub. Au lieu de passer le gestionnaire d'événements Child au parent comme votre exemple, il est possible de l'implémenter comme une «action» et de l'écouter. Considérez-vous cela comme une bonne alternative et une bonne utilisation de Flux?
Pathsofdesign
1
Merci @Pathsofdesign! Cela dépendrait. Flux a ce concept de Controller-Views. Dans cet exemple, il Parentpeut s'agir d'un tel Controller-View, alors qu'il ne Childs'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 de Parentà Childcomme 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/…
chantastic
1
onClick={this.onClick.bind(null, this.state.text)}pas besoin de lier l'état car le parent a cela. si juste onClick={this.onClick}fonctionnera. où onClick = ()=>{const text = this.state.text;..}en parent
Shishir Arora
25

Il semble qu'il y ait une réponse simple. Considère ceci:

var Child = React.createClass({
  render: function() {
    <a onClick={this.props.onClick.bind(null, this)}>Click me</a>
  }
});

var Parent = React.createClass({
  onClick: function(component, event) {
    component.props // #=> {Object...}
  },
  render: function() {
    <Child onClick={this.onClick} />
  }
});

La clé appelle bind(null, this)l' this.props.onClickévénement, transmis par le parent. Maintenant, la fonction onClick accepte les arguments component, 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.

KendallB
la source
les arguments ne sont-ils pas dans le mauvais sens (lieux échangés)?
Le Surrican
1
@TheSurrican Non, c'est très bien. Le premier argument est lié à l' thisinté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é.
manmal
13

La question est de savoir comment passer l'argument de l'enfant au composant parent. Cet exemple est facile à utiliser et testé:

//Child component
class Child extends React.Component {
    render() {
        var handleToUpdate  =   this.props.handleToUpdate;
        return (<div><button onClick={() => handleToUpdate('someVar')}>Push me</button></div>
        )
    }
}

//Parent component
class Parent extends React.Component {
    constructor(props) {
        super(props);
        var handleToUpdate  = this.handleToUpdate.bind(this);
    }

    handleToUpdate(someArg){
        alert('We pass argument from Child to Parent: \n' + someArg);
    }

    render() {
        var handleToUpdate  =   this.handleToUpdate;
        return (<div>
          <Child handleToUpdate = {handleToUpdate.bind(this)} />
        </div>)
    }
}

if(document.querySelector("#demo")){
    ReactDOM.render(
        <Parent />,
        document.querySelector("#demo")
    );
}

Regardez JSFIDDLE

romain
la source
Dans mon cas, il oublie de passer la fonction de rappel dans click ()
Long Nguyen
6

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

class App extends React.Component {
      constructor(){
            super();
            this.handleFilterUpdate = this.handleFilterUpdate.bind(this);
            this.state={name:'igi'}
      }
      handleFilterUpdate(filterValue) {
            this.setState({
                  name: filterValue
            });
      }
   render() {
      return (
        <div>
            <Header change={this.handleFilterUpdate} name={this.state.name} />
            <p>{this.state.name}</p>
        </div>
      );
   }
}

Header.js

class Header extends React.Component {
      constructor(){
            super();
            this.state={
                  names: 'jessy'
            }
      }
      Change(event) {

      // this.props.change(this.state.names);
      this.props.change('jessy');
  }

   render() {
      return (
       <button onClick={this.Change.bind(this)}>click</button>

      );
   }
}

Main.js

import React from 'react';
import ReactDOM from 'react-dom';

import App from './App.jsx';

ReactDOM.render(<App />, document.getElementById('app'));

C'est tout, vous pouvez maintenant transmettre des valeurs de votre client au serveur.

Jetez un œil à la fonction Change dans Header.js

Change(event) {
      // this.props.change(this.state.names);
      this.props.change('jessy');
  }

Voici comment vous poussez des valeurs dans les accessoires du client vers le serveur

Ignace Andrew
la source
Puis-je savoir C'est ainsi que vous poussez des valeurs dans les accessoires du client vers le serveur, qu'entendez-vous par cette déclaration
G1P
2

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)

  1. Assurez-vous que dans le constructeur parent vous liez la fonction que vous avez créée dans le parent
  2. Passez la fonction liée à l'enfant comme accessoire (pas de lambda car nous passons une référence à la fonction)
  3. Appelez la fonction liée à partir d'un événement enfant (Lambda! Nous appelons la fonction lorsque l'événement est déclenché. Si nous ne le faisons pas, la fonction s'exécutera automatiquement en charge et ne sera pas déclenchée sur l'événement.)

Fonction parent

handleFilterApply(filterVals){} 

Constructeur parent

this.handleFilterApply = this.handleFilterApply.bind(this);

Prop transmis à l'enfant

onApplyClick = {this.handleFilterApply}

Appel d'événement enfant

onClick = {() => {props.onApplyClick(filterVals)}
Jordan H
la source
0

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:

interface SymptomChooserState {
  // true when a symptom was pressed can now add more detail
  isInDetailMode: boolean
  // since when user has this symptoms
  sinceDate: Date,
}

class SymptomChooser extends Component<{}, SymptomChooserState> {

  state = {
    isInDetailMode: false,
    sinceDate: new Date()
  }

  helloParent(symptom: Symptom) {
    console.log("This is parent of: ", symptom.props.name);
    // TODO enable detail mode
  }

  render() {
    return (
      <View>
        <Symptom name='Fieber' callback={this.helloParent.bind(this)} />
      </View>
    );
  }
}

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é):

interface SymptomProps {
  // name of the symptom
  name: string,
  // callback to notify SymptomChooser about selected Symptom.
  callback: (symptom: Symptom) => void
}

class Symptom extends Component<SymptomProps, SymptomState>{

  state = {
    isSelected: false,
    severity: 0
  }

  selectedSymptom() {
    this.setState({ isSelected: true });
    this.props.callback(this);
  }

  render() {
    return (
      // symptom is not selected
      <Button
        style={[AppStyle.button]}
        onPress={this.selectedSymptom.bind(this)}>
        <Text style={[AppStyle.textButton]}>{this.props.name}</Text>
      </Button>
    );
  }
}
drewjosh
la source