Esta siguiente función de devolución de llamada onClick provocará 1 re-procesamiento:
const handleClickSync = () => { // Order of setters doesn't matter - React lumps all state changes together // The result is one single re-rendering setValue("two"); setIsCondition(true); setNumber(2); };React agrupa los tres cambios de estado y provoca 1 renderización.
Sin embargo, la siguiente función de devolución de llamada onClick provocará 3 nuevas representaciones:
const handleClickAsync = () => { setTimeout(() => { // Inside of an async function (here: setTimeout) the order of setter functions matters. setValue("two"); setIsCondition(true); setNumber(2); }); }; Es una nueva representación para cada setter de useState . Además, el orden de los setters influye en los valores de cada una de estas representaciones.
Pregunta : ¿Por qué el hecho de que hago que la función sea asíncrona (aquí a través setTimeout ) hace que los cambios de estado sucedan uno tras otro y, por lo tanto, provocan 3 re-renderizaciones? ¿Por qué React agrupa estos cambios de estado si la función es síncrona para causar solo una repetición?
Puede jugar con este CodeSandBox para experimentar el comportamiento.
En este momento, reacciona solo los lotes sincronizan setState s dentro de los controladores de eventos. Pero en reaccionar 18 estará disponible en setTimeout , useEffect s, etc. Aquí hay una excelente explicación de Dan https://github.com/reactwg/react-18/discussions/21
Si la ejecución del código comienza dentro de reaccionar (p. ej., un oyente onClick o un useEffect de uso), entonces reaccionar puede estar seguro de que después de haber realizado todos los ajustes de estado, la ejecución volverá a reaccionar y puede continuar desde allí. Entonces, para estos casos, puede permitir que la ejecución del código continúe, esperar el retorno y luego hacer un solo renderizado sincrónicamente.
Pero si la ejecución del código comienza aleatoriamente (por ejemplo, en un setTimeout o al resolver una promesa), entonces el código no volverá a reaccionar cuando haya terminado. Entonces, desde la perspectiva de reaccionar, estaba durmiendo tranquilamente y luego llamas a setState , obligando a reaccionar a decir "¡ahhh! ¡Están configurando el estado! Será mejor que renderice". Hay formas asincrónicas en las que reaccionar podría esperar para ver si está haciendo algo más (por ejemplo, un tiempo de espera 0 o una microtarea), pero no hay una forma sincrónica de reaccionar para saber cuándo ha terminado.
En la versión actual de reaccionar, puede decirle a reaccionar para procesar por lotes múltiples cambios usando unstable_batchedUpdates :
import { unstable_batchedUpdates } from "react-dom"; const handleClickAsync = () => { setTimeout(() => { unstable_batchedUpdates(() => { setValue("two"); setIsCondition(true); setNumber(2); }); }); };Una vez que llegue React 18, esto no será necesario, ya que los cambios que han realizado en el renderizado para el modo concurrente eliminarán la necesidad de esto.