Réponse courte :
React garantit que les références sont définies avant componentDidMount
o componentDidUpdate
crochets. Mais seulement pour les enfants qui a été rendu .
componentDidMount() {
// can use any refs here
}
componentDidUpdate() {
// can use any refs here
}
render() {
// as long as those refs were rendered!
return <div ref={/* ... */} />;
}
Notez que cela ne signifie pas que "React fixe toujours tous les arbitres avant que ces crochets ne fonctionnent".
Regardons quelques exemples où les arbitres Ne le fais pas. se mettre en place.
Les références ne sont pas définies pour les éléments qui n'ont pas été rendus.
React n'appellera les callbacks ref que pour les éléments que vous avez réellement retourné par le rendu .
Cela signifie que si votre code ressemble à
render() {
if (this.state.isLoading) {
return <h1>Loading</h1>;
}
return <div ref={this._setRef} />;
}
et initialement this.state.isLoading
es true
vous devriez no s'attendre à this._setRef
à appeler avant componentDidMount
.
Cela devrait avoir un sens : si votre premier rendu a retourné <h1>Loading</h1>
il n'y a aucun moyen pour React de savoir que dans une autre condition, il retourne quelque chose d'autre qui nécessite une référence pour être attaché. Il y a aussi rien pour mettre la référence : le site <div>
n'a pas été créé parce que l'élément render()
La méthode a dit que ça ne devrait pas être rendu.
Donc, dans cet exemple, seulement componentDidMount
se déclenchera. Cependant, quand this.state.loading
les changements apportés à false
vous verrez this._setRef
attaché d'abord, et ensuite componentDidUpdate
fera feu.
Attention aux autres composants
Notez que si vous passez des enfants avec des références vers le bas à d'autres composants il y a une chance qu'ils fassent quelque chose qui empêche le rendu (et qui cause le problème).
Par exemple, ceci :
<MyPanel>
<div ref={this.setRef} />
</MyPanel>
ne fonctionnerait pas si MyPanel
ne comprenait pas props.children
dans sa sortie :
function MyPanel(props) {
// ignore props.children
return <h1>Oops, no refs for you today!</h1>;
}
Encore une fois, ce n'est pas un bug : il n'y aurait rien pour React pour définir la référence parce que l'élément DOM n'a pas été créé. .
Les références ne sont pas placées avant les cycles de vie si elles sont passées à une méthode imbriquée ReactDOM.render()
Comme dans la section précédente, si vous transmettez un enfant avec une référence à un autre composant, il est possible que ce composant fasse quelque chose qui empêche de joindre la référence à temps.
Par exemple, il se peut qu'il ne renvoie pas l'enfant à partir de render()
et appelle plutôt ReactDOM.render()
dans un crochet de cycle de vie. Vous pouvez trouver un exemple de ceci aquí . Dans cet exemple, nous rendons :
<MyModal>
<div ref={this.setRef} />
</MyModal>
Mais MyModal
effectue un ReactDOM.render()
appeler son componentDidUpdate
la méthode du cycle de vie :
componentDidUpdate() {
ReactDOM.render(this.props.children, this.targetEl);
}
render() {
return null;
}
Depuis React 16, de tels les appels de rendu de niveau supérieur pendant un cycle de vie seront retardés jusqu'à ce que les cycles de vie aient été exécutés pour l'ensemble de l'arbre. . Cela expliquerait pourquoi vous ne voyez pas les refs attachés à temps.
La solution à ce problème est d'utiliser portails au lieu d'être imbriqués ReactDOM.render
appels :
render() {
return ReactDOM.createPortal(this.props.children, this.targetEl);
}
De cette façon, notre <div>
avec une référence est réellement incluse dans la sortie du rendu.
Donc, si vous rencontrez ce problème, vous devez vérifier qu'il n'y a rien entre votre composant et la référence qui pourrait retarder le rendu des enfants.
N'utilisez pas setState
pour stocker les références
Assurez-vous que vous n'utilisez pas setState
pour stocker la ref dans la callback ref, car elle est asynchrone et avant qu'elle ne soit "terminée", componentDidMount
sera exécuté en premier.
Toujours un problème ?
Si aucun des conseils ci-dessus ne vous aide, déposez un problème dans React et nous y jetterons un œil.
6 votes
Je me trompe peut-être, mais lorsque vous utilisez la fonction flèche pour les méthodes de rendu, elle capturera la valeur de
this
à partir du champ lexical en dehors de votre classe. Essayez de vous débarrasser de la syntaxe de la fonction flèche pour les méthodes de votre classe et voyez si cela vous aide.0 votes
Cela fonctionne bien pour moi. Êtes-vous sûr que les appels de rappel de refs après DidMount ? Faites 2 console.logs dans les deux fonctions et voyez laquelle était la première
0 votes
J'utilise la version 15.5.4 de React.
0 votes
Je pense que vous avez raison au sujet de l'ordre. Je pensais juste que le problème pouvait venir de l'étendue lexicale :)
3 votes
@GProst C'est la nature de ma question. J'ai mis console.log dans les deux fonctions et componentDidMount s'exécute en premier, le callback ref en second.
0 votes
Y a-t-il un moyen pour vous de montrer tout le code de vos composants ? Je viens d'installer react 15.4.1 et de définir les méthodes render et componentDidMound comme une fonction flèche (comme vous l'avez fait) et tout fonctionne bien...
0 votes
@GProst Il y a peut-être quelque chose de plus important à l'œuvre ici, c'est une base de code (propriétaire) assez importante. Je pense que j'ai posté les parties pertinentes ici. Il est bon de savoir que j'ai les bonnes hypothèses sur la façon dont il devrait fonctionner au moins, mais toujours aucune idée de la façon de résoudre le problème.
3 votes
J'ai eu un problème similaire pour nous, en fait, nous l'avons raté lors de la phase initiale
render
et devait donc s'appuyer surcomponentDidUpdate
commecomponentDidMount
ne fait pas partie de la mise à jour cycle de vie . Ce n'est probablement pas votre problème, mais j'ai pensé que cela pourrait être une solution potentielle.0 votes
Def a good poing @AlexanderNied J'ai vu/fait la même chose dans d'autres circonstances. Je n'étais pas concerné par ce problème à ce moment-là, mais je prendrai en compte cette suggestion si je peux y revenir à l'avenir !
4 votes
Même chose avec React 16. La documentation indique clairement
ref callbacks are invoked before componentDidMount or componentDidUpdate lifecycle hooks.
mais cela ne semble pas être vrai :(1 votes
1. la déclaration de la flèche réf est :
ref = {ref => { this.drawerRef = ref }}
2. même les refs sont invoquées avant componentDidMount ; les refs ne sont accessibles qu'après le rendu initial, lorsque le div dans votre cas est rendu. Ainsi, vous devez être en mesure d'accéder à la référence au niveau suivant, c'est-à-dire dans componentWillReceiveProps, en utilisant la commandethis.drawerRef
3. Si vous essayez d'accéder avant le montage initial, vous n'obtiendrez que des valeurs indéfinies de la référence.0 votes
Bonjour à tous, si vous trouvez des problèmes dans React, veuillez déposer un bug la prochaine fois ! Merci.
0 votes
J'ai posté une autre réponse qui pourrait expliquer ce qui se passe.