En primer lugar, estoy clonando Youtube para practicar. Creé el controlador de eventos handleSearch para obtener videos de la palabra clave de búsqueda.
const App = ({ youtube }) => { const [videos, setVideos] = useState([]); const [selectedVideo, setSelectedVideo] = useState(null); const [loading, setLoading] = useState(false); const handleSearch = useCallback((q) => { setLoading(true); console.log("loading -> true"); // 1 setSelectedVideo(null); console.log("selectedVideo -> null"); // 2 // 3 Component rendering youtube.search(q).then((videos) => { console.log("Before setVideos"); // 4 setVideos(videos.map((video) => ({ ...video, id: video.id.videoId }))); console.log("After setVideos"); // 5 setLoading(false); console.log("loading -> false"); // 6 }); // 7 Component rendering }, []); return ( <> {console.log("Component rendering")} ... youtube es una clase que existe en otro archivo; puede ejecutar fetch .
De todos modos, escribí 7 comentarios arriba sobre el momento en que se imprime algo en la consola. (Y mi consola abajo)
Pero no puedo entender esa primera representación (la tercera impresa).
Según la respuesta de Dan Abramov: https://stackoverflow.com/a/48610973/17356311 ,
La clave para comprender esto es que no importa cuántas llamadas setState() en cuántos componentes haga dentro de un controlador de eventos React, producirán solo una nueva representación al final del evento.
Entonces, si en su ejemplo tuviéramos un controlador de respuesta AJAX en lugar de handleClick, cada setState() se procesaría inmediatamente a medida que suceda. En este caso, sí, verías un estado intermedio:
setState en los controladores de eventos se procesan por lotes, pero no en los controladores de respuesta. ¿Correcto?
Entonces, si la consola hubiera impreso 1 -> 2 -> 4 -> Representación de componentes -> 5 -> 6 -> Representación de componentes , habría entendido por qué se representó dos veces. Pero ahora la secuencia es extraña...
¿Por qué este componente se procesa después de establecer el video selectedVideo en null?
En primer lugar, debe saber que "React puede agrupar varias llamadas setState() en una sola actualización para el rendimiento", según la documentación de React . Cuando llama su devolución de llamada "handleSearch", agrupa todos los cambios de estado en esa función en particular y los llama juntos. También llama a una promesa, para lo cual es una devolución de llamada "entonces", no puede saber cuánto debe esperar. Por lo tanto, deja de agrupar los cambios de estado y se vuelve a renderizar. Ese es el primer renderizado. Luego, en algún momento, se llama a la microtarea para la promesa ("luego" devolución de llamada), y en esa devolución de llamada se agrupan y llaman juntos otros dos cambios de estado, por lo que es una segunda repetición.
Según su código, youtube.search devuelve una promesa que no bloquea la ejecución de handleSearch . El .then está asociando un controlador para el eventual éxito de esa llamada. Entonces, básicamente está diciendo, ejecute esta acción asincrónica, y cuando termine (tenga éxito), regrese y ejecute esto. Su componente termina volviendo a renderizarse porque la devolución de llamada de handleSearch terminó de ejecutarse y usted modificó el estado: setLoading(true) y setSelectedVideo(null) . Eventualmente, su llamada de promesa se resuelve y su devolución de llamada se ejecuta modificando el estado dos veces nuevamente, lo que provoca la segunda representación.