messerbill
messerbill

Reputation: 5639

How does the react library rerender components

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.logs 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

Answers (1)

Dennis Vash
Dennis Vash

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

Related Questions