Estoy viendo Paul O Shannessy - Building React From Scratch
Y entiendo muy bien el proceso de montaje, pero tengo un día difícil tratando de entender cómo React actualiza un componente y sus hijos.
El reconciliador controla el proceso de actualización mediante este método:
function receiveComponent(component, element) { let prevElement = component._currentElement; if (prevElement === element) { return; } component.receiveComponent(element); } Component.receiveComponent
receiveComponent(nextElement) { this.updateComponent(this._currentElement, nextElement); } y este es el método Component.updateComponent :
updateComponent(prevElement, nextElement) { if (prevElement !== nextElement) { // React would call componentWillReceiveProps here } // React would call componentWillUpdate here // Update instance data this._currentElement = nextElement; this.props = nextElement.props; this.state = this._pendingState; this._pendingState = null; let prevRenderedElement = this._renderedComponent._currentElement; let nextRenderedElement = this.render(); if (shouldUpdateComponent(prevRenderedElement, nextRenderedElement)) { Reconciler.receiveComponent(this._renderedComponent, nextRenderedElement); } }Esta es la parte del código que actualiza el componente después del cambio de estado, y asumo que también debería actualizar a los elementos secundarios, pero no puedo entender cómo este código logra eso, en el proceso de montaje, React crea instancias de componentes para profundizar en el tree pero esto no sucede aquí, necesitamos encontrar el primer elemento HTML, luego podemos cambiar nuestra estrategia y actualizar ese elemento HTML en otro lugar del código, y no puedo encontrar ninguna forma de encontrar ningún elemento HTML de esta manera .
Encontrar el primer HTML es la manera de detener esta recursividad interminable y, lógicamente, esto es lo que espero del código, detener la recursividad de la misma manera en el proceso de montaje, pero en el montaje, esta instanciación exigió el componente para que podamos delegar al reconciliador que descubrirá que estamos tratando con una instancia contenedora de un elemento HTML, no una instancia contenedora de un componente personalizado, entonces React puede colocar ese elemento HTML en el DOM.
No puedo entender cómo funciona el código en el proceso de actualización. este código, como veo, no profundizará en el árbol y creo que no actualizará a los elementos secundarios y no puedo dejar que React encuentre el primer elemento HTML para que React pueda actualizar el elemento DOM, ¿no es así?
Este es el repositorio de código en Github
Creo que React no vuelve a renderizar el componente principal primero en lugar de eso, React vuelve a renderizar el componente secundario primero.
Ejemplo: A (padre) -> B (hijo) -> C (hijo de B) Cuando A actualiza el estado C (volver a renderizar) -> B -> A
Hola, considere usar una estructura de datos de árbol para su necesidad, ReactJs sigue una manera unidireccional de actualizar el estado, es decir, tan pronto como haya un cambio en el estado principal, todos los elementos secundarios se transmiten a los accesorios que residen en el componente principal. se actualizan de una vez por todas! Considere usar algo conocido como búsqueda en profundidad como una opción de algo que le encontrará el nodo que se conecta al padre y una vez que llegue a ese nodo, verificará el estado y si hay una desviación de las variables de estado que son compartidas por el padre puede actualizarlos!
Nota: Todo esto puede parecer un poco teórico, pero si pudieras hacer algo remotamente parecido a esto, ¡habrías creado una forma de actualizar los componentes tal como lo hace React!
Experimentalmente descubrí que React solo volverá a renderizar elementos si es necesario, lo cual es siempre, excepto {children} y React.memo() .
El uso correcto de los niños, junto con las actualizaciones de dom por lotes, hace que la experiencia del usuario sea muy eficiente y fluida.
considera este caso:
function App() { return <div> <Parent> <Child01/> <Child01/> </Parent> <Child03/> </div> } function Parent({children}) { const [state, setState] = useState(0); return <div> <button onClick={x => x+1)>click</button> <Child02 /> {children} </div> }al hacer clic en el botón, obtendrá lo siguiente:
- button click - setState(...), add Parent to dirty list - start re-rendering all dirty nodes - Parent rerenders - Child02 rerenders - DONETenga en cuenta que
app ) y hermano ( Child03 ) no se volverán a renderizar, o terminará con una repetición de renderizado.Parent se vuelve a renderizar porque su estado ha cambiado, por lo que su salida debe volver a calcularse.{children} no se ha visto afectado por este cambio, por lo que permanece igual. (a menos que haya un contexto involucrado, pero ese es un mecanismo diferente).<Child02 /> ha sido marcado sucio, porque esa parte del dominio virtual ha sido tocada. Si bien es trivial para nosotros ver que no se efectuó, la única forma en que React podría verificarlo es comparando accesorios, ¡lo cual no se hace de manera predeterminada!React.memo , que podría ser más lento que volver a renderizarlo.Otra respuesta podría ser la estructura del árbol de fibra. Durante la ejecución, react convierte un ReactComponent en un objeto hecho de ReactNode y props. Estos ReactNode s se ensamblan en un árbol FiberNode (¿cuál podría ser la representación en memoria del dominio virtual?).
En el árbol de FiberNode , según el algoritmo transversal (los niños primero, los hermanos primero, etc.), React siempre tiene un único nodo "siguiente" para continuar. Por lo tanto, React profundizará en el árbol y actualizará los FiberNode a medida que avanza.
Si tomamos el mismo ejemplo,
function App() { return <div> <Parent> <Child01/> <Child01/> </Parent> <Child03/> </div> } function Parent({children}) { const [state, setState] = useState(0); return <div> <button onClick={x => x+1)>click</button> <Child02 /> {children} </div> }Qué React se transformará en este árbol de FiberNode:
node01 = { type: App, return: null, child: node02, sibling: null } node02 = { type: 'div', return: node01, child: node03, sibling: null } node03 = { type: Parent, return: node02, child: node05(?), sibling: node04 } node04 = { type: Child03, return: node02, child: null, sibling: null } node05 = { type: Child01, return: node03, child: null, sibling: node06 } node06 = { type: Child01, return: node03, child: null, sibling: null } // Parent will spawn its own FiberTree, node10 = { type: 'div', return: node02, child: node11, sibling: null } node11 = { type: 'button', return: node10, child: null, sibling: node12 } node12 = { type: Child02, return: node10, child: null, sibling: node05 }Es posible que me haya perdido algo (es decir, el hijo de node03 podría ser node10), pero la idea es esta: React siempre tiene un solo nodo (el 'siguiente' nodo) para representar cuando atraviesa el árbol de fibra.