J'essaie de passer une ref d'un composant à un autre composant. Puisque les références de chaîne sont obsolètes J'utilise les références de rappel.
J'ai donc quelque chose de similaire à ceci:
<One ref={c => this.one = c}/>
<Two one={this.one}/>
Le problème est que chaque fois que j'essaie d'accéder à this.props.one
dans Two
, je reçois undefined
.
J'ai même essayé ceci sur Two
:
componentDidMount(){
setTimeout(()=>{
console.log(this.props.one);
},5000)
}
Il semble que le problème est que lors de la création de l'accessoire, la référence n'existe pas encore car il est créé une fois que One
est monté. Mais je ne sais pas comment "actualiser" les accessoires sur Two
pour obtenir la référence du composant monté.
Alors, quelle est la bonne façon de passer une référence à un autre composant?
Modifier
Certains utilisateurs ont suggéré d'encapsuler cette logique dans un composant supérieur, ce qui en soi rend ces autres composants enfants.
Le problème avec cette approche est que vous ne pouvez pas créer de logique réutilisable et que vous devez répéter la même logique à plusieurs reprises dans ces composants d'encapsulation.
Supposons que vous souhaitiez créer un composant <Form>
générique qui encapsule la logique de soumission dans votre magasin, vérifie les erreurs, etc. Et vous procédez comme suit:
<Form>
<Input/>
<Input/>
<Input/>
<Input/>
<SubmitButton/>
</Form>
Dans cet exemple, <Form>
ne peut pas accéder aux instances (et méthodes) des enfants, car this.props.children
ne renvoie pas ces instances. Il retourne une liste de pseudo composants.
Alors, comment pouvez-vous vérifier si un certain <Input/>
a détecté une erreur de validation sans passer une référence?
Vous devez encapsuler ces composants dans un autre composant avec la logique de validation. Par exemple, dans <UserForm>
. Mais comme chaque formulaire est différent, la même logique doit être copiée dans <CategoryForm>
, <GoupForm>
, etc. Ceci est terriblement inefficace, c'est pourquoi je souhaite encapsuler la logique de validation dans <Form>
et transmettre les références des composants <Input>
à <Form>
.
En général, la fonction "ref" est un anti-motif dans React. Il existe pour permettre un développement axé sur les effets secondaires. Toutefois, pour tirer le meilleur parti de la méthode de programmation React, vous devez éviter autant que possible les "références".
En ce qui concerne votre problème particulier, passer un enfant à un de ses frères et sœurs est un scénario poulet contre œuf. Le rappel ref est déclenché lorsque l’enfant est monté et non pendant le rendu, c’est pourquoi votre exemple ne fonctionne pas. Une chose que vous pouvez essayer est de pousser l’arbitre dans un état puis de le lire dans l’autre enfant. Alors:
<One ref={c => !this.state.one && this.setState({ one: c })}/>
<Two one={this.state.one}/>
Remarque: sans le !this.state.one
, la boucle sera infinie.
Voici un exemple codepen de ce fonctionnement (regardez sur la console pour voir le code de référence enregistré): http://codepen.io/anon/pen/pbqvRA
En général, si vous devez transmettre une référence à quelque chose qui peut ne pas être défini au moment de l'appel, vous pouvez passer un lambda à la place:
<One ref={c => this.one = c}/>
<Two one={() => this.one}/>
et ensuite référencer comme
this.props.one()
S'il a été défini lorsque vous l'appelez, vous obtiendrez une valeur. Avant cela, vous aurez undefined
(en supposant que cela n’ait pas été initialisé autrement).
Cela vaut la peine de noter que vous ne referez pas nécessairement le rendu lorsqu'il sera disponible, et je m'attendrais à ce qu'il soit undefined
lors du premier rendu. C'est quelque chose que l'utilisation de state pour conserver votre référence est gérée, mais vous n'obtiendrez pas plus d'un rendu.
Compte tenu de tout cela, je recommanderais de déplacer le code qui utilise la référence à One
dans Two
dans le composant qui rend One
et Two
, afin d'éviter tous les problèmes liés à la fois à cette stratégie et à celle de @Carl Sverre.