Respuesta corta:
React garantiza que las referencias se establezcan antes componentDidMount
o componentDidUpdate
enganches. Pero solo para niños que realmente se renderizaron .
componentDidMount() {
}
componentDidUpdate() {
}
render() {
return <div ref={/* ... */} />;
}
Tenga en cuenta que esto no significa que "React siempre establece todas las referencias antes de que se ejecuten estos ganchos".
Veamos algunos ejemplos en los que los árbitros no se establecen.
Las referencias no se establecen para elementos que no se renderizaron
React solo llamará a las devoluciones de llamada de referencia para los elementos que realmente devolvió del renderizado .
Esto significa que si su código se parece a
render() {
if (this.state.isLoading) {
return <h1>Loading</h1>;
}
return <div ref={this._setRef} />;
}
y en un principio this.state.isLoading
es true
, usted debe no esperar this._setRef
a ser llamado antes componentDidMount
.
Esto debería tener sentido: si su primer render regresó <h1>Loading</h1>
, no hay forma posible de que React sepa que bajo alguna otra condición devuelve algo más que necesita una referencia adjunta. Tampoco hay nada para establecer la referencia: el <div>
elemento no fue creado porque el render()
método dijo que no debería ser renderizado.
Entonces, con este ejemplo, solo componentDidMount
se disparará. Sin embargo, cuando this.state.loading
cambie afalse
, verá this._setRef
adjunto primero y luego componentDidUpdate
disparará.
Cuidado con otros componentes
Tenga en cuenta que si pasa a los niños con referencias a otros componentes, existe la posibilidad de que estén haciendo algo que evite la representación (y cause el problema).
Por ejemplo, esto:
<MyPanel>
<div ref={this.setRef} />
</MyPanel>
no funcionaría si MyPanel
no incluyera props.children
en su salida:
function MyPanel(props) {
return <h1>Oops, no refs for you today!</h1>;
}
Nuevamente, no es un error: no habría nada para que React establezca la referencia porque el elemento DOM no fue creado .
Las referencias no se establecen antes de los ciclos de vida si se pasan a un anidado ReactDOM.render()
Al igual que en la sección anterior, si pasa un hijo con una referencia a otro componente, es posible que este componente haga algo que impida adjuntar la referencia a tiempo.
Por ejemplo, tal vez no está devolviendo al hijo de render()
, sino que está llamando ReactDOM.render()
a un enlace de ciclo de vida. Puedes encontrar un ejemplo de esto aquí . En ese ejemplo, renderizamos:
<MyModal>
<div ref={this.setRef} />
</MyModal>
Pero MyModal
realiza una ReactDOM.render()
llamada en su componentDidUpdate
método de ciclo de vida:
componentDidUpdate() {
ReactDOM.render(this.props.children, this.targetEl);
}
render() {
return null;
}
Desde React 16, estas llamadas de procesamiento de nivel superior durante un ciclo de vida se retrasarán hasta que los ciclos de vida se hayan ejecutado para todo el árbol . Esto explicaría por qué no ve los árbitros adjuntos a tiempo.
La solución a este problema es utilizar
portales en lugar de ReactDOM.render
llamadas anidadas :
render() {
return ReactDOM.createPortal(this.props.children, this.targetEl);
}
De esta manera, nuestro <div>
con una referencia se incluye realmente en la salida de render.
Entonces, si encuentra este problema, debe verificar que no haya nada entre su componente y la referencia que pueda retrasar la representación de los niños.
No lo use setState
para almacenar referencias
Asegúrese de que no está usando setState
para almacenar la referencia en la devolución de llamada de referencia, ya que es asincrónica y antes de que "termine", componentDidMount
se ejecutará primero.
¿Sigue siendo un problema?
Si ninguno de los consejos anteriores le ayuda, presente un problema en React y le echaremos un vistazo.
this
ámbito léxico fuera de su clase. Intente deshacerse de la sintaxis de la función de flecha para sus métodos de clase y vea si ayuda.