TL; DR
¿Cómo puede un componente principal saber cuándo ha finalizado la representación de cada componente secundario y el DOM visible para el usuario con su versión más actualizada?
Digamos que tengo un componente component A
secundario Grid
que consta de 3x3
componentes de nieto. Cada uno de esos componentes nietos obtiene datos de un punto final de API tranquilo y se representa cuando los datos están disponibles.
Me gustaría cubrir toda el área Component A
con un loader
marcador de posición, que se revelará solo cuando el último de los componentes en la cuadrícula haya obtenido los datos con éxito y los haya procesado, de modo que ya esté en el DOM y se pueda ver.
La experiencia del usuario debe ser una transición súper suave de "cargador" a una grilla completamente poblada sin parpadeo.
Mi problema es saber exactamente cuándo revelar los componentes debajo del cargador.
¿Hay algún mecanismo en el que pueda confiar para hacer esto con absoluta precisión? No codifico un límite de tiempo para el cargador. Según tengo entendido, confiar en ComponentDidMount
cada niño tampoco es confiable, ya que en realidad no garantiza que el componente sea completamente visible para el usuario en el momento de la llamada.
Para destilar la pregunta aún más:
Tengo un componente que representa algún tipo de datos. Después de que se inicializa, no lo tiene, por lo
componentDidMount
que llega a un punto final API para él. Una vez que recibe los datos, está cambiando su estado para reflejarlos. Es comprensible que esto provoque una nueva representación del estado final de ese componente. Mi pregunta es la siguiente: ¿Cómo sé cuando que volver a hacer ha tenido lugar y se refleja en el DOM frente del usuario. Ese punto en el tiempo! = El punto en el tiempo cuando el estado del componente ha cambiado para contener datos.
ComponentDidMount
que estoy usandoaxios
para obtener datos. cuando llegan los datos, cambio el estado de ese componente que causa una representación de los datos. En teoría, 8 componentes secundarios pueden obtener en 3 segundos, y el último tomaría 15 segundos ...Respuestas:
Hay dos ganchos de ciclo de vida en React que se invocan después de que se ha procesado el DOM de un componente:
Para su caso de uso de sus padres componente P está interesado en N componentes hijos tienen cada uno satisfecho alguna condición X . X se puede definir como una secuencia:
Al combinar el estado del componente y usar el
componentDidUpdate
gancho, puede saber cuándo se ha completado la secuencia y si su componente cumple la condición X.Puede realizar un seguimiento de cuándo se ha completado su operación asincrónica configurando una variable de estado. Por ejemplo:
Después de configurar el estado, React llamará a la
componentDidUpdate
función de sus componentes . Al comparar los objetos de estado actuales y anteriores dentro de esta función, puede indicarle al componente principal que su operación asíncrona se ha completado y que el estado de su nuevo componente ha generado:En su componente P, puede usar un contador para realizar un seguimiento de cuántos niños han actualizado de manera significativa:
Finalmente, al conocer la longitud de N , puede saber cuándo se han producido todas las actualizaciones significativas y actuar en consecuencia en su método de representación de P :
fuente
Lo configuraría para que confíe en una variable de estado global para indicar a sus componentes cuándo renderizar. Redux es mejor para este escenario en el que muchos componentes están hablando entre sí, y usted mencionó en un comentario que a veces lo usa. Entonces esbozaré una respuesta usando Redux.
Habría que mover sus llamadas a la API al contenedor principal,
Component A
. Si desea que sus nietos se procesen solo después de que se completen las llamadas API, no puede mantener esas llamadas API en los nietos mismos. ¿Cómo se puede hacer una llamada API desde un componente que aún no existe?Una vez que se realizan todas las llamadas a la API, puede usar acciones para actualizar una variable de estado global que contiene un montón de objetos de datos. Cada vez que se reciben datos (o se detecta un error), puede enviar una acción para verificar si su objeto de datos está completamente lleno. Una vez que se haya completado por completo, puede actualizar una
loading
variablefalse
y renderizar condicionalmente suGrid
componente.Así por ejemplo:
Su reductor contendrá el objeto de estado global que dirá si las cosas están listas para funcionar o no:
En tus acciones:
Aparte
Si realmente está casado con la idea de que sus llamadas API viven dentro de cada nieto, pero que la cuadrícula completa de nietos no se procesa hasta que se completen todas las llamadas API, tendría que usar una solución completamente diferente. En este caso, sus nietos tendrían que ser representados desde el principio para hacer sus llamadas, pero tienen una clase css con
display: none
, que solo cambia después de que la variable de estado globalloading
se marca como falsa. Esto también es factible, pero además del punto de Reaccionar.fuente
Potencialmente podría resolver esto usando React Suspense.
La advertencia es que no es una buena idea suspender más allá del árbol de componentes que realiza el procesamiento (es decir: si su componente inicia un proceso de procesamiento, no es una buena idea suspender ese componente, en mi experiencia), por lo que es probablemente una mejor idea para iniciar las solicitudes en el componente que representa las celdas. Algo como esto:
Ahora, de qué manera el suspenso se combina con Redux, no estoy seguro. La idea general detrás de esta versión (¡experimental!) De Suspense es que inicie la búsqueda inmediatamente durante el ciclo de renderizado de un componente padre y pase un objeto que represente una búsqueda a los hijos. Esto evita que tenga que tener algún tipo de objeto de barrera (que necesitaría en otros enfoques).
¡Diré que no creo que esperar hasta que todo se haya recuperado para mostrar algo sea el enfoque correcto porque la interfaz de usuario será tan lenta como la conexión más lenta o puede que no funcione en absoluto!
Aquí está el resto del código faltante:
Y un sandbox: https://codesandbox.io/s/falling-dust-b8e7s
fuente
En primer lugar, el ciclo de vida podría tener un método asíncrono / espera.
Lo que necesitamos saber
componentDidMount
ycomponentWillMount
,En mi consideración, simplemente implementarlos usando el ciclo de vida normal sería lo suficientemente bueno.
Material-UI CircularProgress
Debido a que la representación infantil hace que los padres hagan lo mismo, atraparlo
didUpdate
estaría bien.Y, dado que se llama después del renderizado, las páginas no deberían cambiarse después de eso si configura la función de verificación como su demanda.
Usamos esta implementación en nuestro producto que tiene una API que hace que los 30 obtengan la respuesta, todo funcionó bien hasta donde veo.
fuente
Como usted está haciendo una llamada a la API en
componentDidMount
, cuando la llamada a la API resolverá tendrá los datos encomponentDidUpdate
que este ciclo de vida que va a pasarprevProps
yprevState
. Entonces puedes hacer algo como a continuación:Si desea saber esto antes de que se procese el componente, puede usarlo
getSnapshotBeforeUpdate
.https://reactjs.org/docs/react-component.html#getsnapshotbeforeupdate .
fuente
Hay varios enfoques con los que puede ir:
fuente