Reputation: 5639
I am trying to figure out how the react library rerenders components after updating the props
. Therefor I kind of monkey patched ReactDOM.render
method like so:
const oldRender = ReactDOM.render
ReactDOM.render = function(){
// ......
console.log("42")
return oldRender.call(this, ...arguments, () => {
console.log("done")
document.dispatchEvent(new Event('react-dom-rendered'))
})
}
This works for the first rendering cylce. But after the props
of the rendered component changed, the console.log
s are not printed anymore. In order to figure out why I read in the docs that ReactDOM.render
will only be called once. So I searched through google just like through react's sources but I was not able to find out how react manages to rerender a component after a props update. Could you help me here?
Upvotes: 2
Views: 157
Reputation: 53994
ReactDom.render
called once to mount the component into the DOM.
On state update or on props change, React starts a Reconciliation process.
When a component’s props or state change, React decides whether an actual DOM update is necessary by comparing the newly returned element with the previously rendered one. When they are not equal, React will update the DOM. This process is called “reconciliation”.
In this process, React runs a pretty simple diff algorithm while traversing a copy of Virtual DOM.
Want to implement the Reconciliation? See Build your own React and its repo.
function reconcileChildren(wipFiber, elements) {
let index = 0
let oldFiber =
wipFiber.alternate && wipFiber.alternate.child
let prevSibling = null
while (
index < elements.length ||
oldFiber != null
) {
const element = elements[index]
let newFiber = null
const sameType =
oldFiber &&
element &&
element.type == oldFiber.type
if (sameType) {
newFiber = {
type: oldFiber.type,
props: element.props,
dom: oldFiber.dom,
parent: wipFiber,
alternate: oldFiber,
effectTag: "UPDATE",
}
}
if (element && !sameType) {
newFiber = {
type: element.type,
props: element.props,
dom: null,
parent: wipFiber,
alternate: null,
effectTag: "PLACEMENT",
}
}
if (oldFiber && !sameType) {
oldFiber.effectTag = "DELETION"
deletions.push(oldFiber)
}
if (oldFiber) {
oldFiber = oldFiber.sibling
}
if (index === 0) {
wipFiber.child = newFiber
} else if (element) {
prevSibling.sibling = newFiber
}
prevSibling = newFiber
index++
}
}
Upvotes: 2