Clearly we took a shortcut in the former one. The mounting process is expensive. It's quite like building everything from scratch. We do not want to do that in each render. In react, the real render function looks something like this:
Node
Right now, the render that we've been talking about is the ReactDOM.render, not the render function that lives in a React component.
function render(element, node) {
// First check if we've already rendered into this node.
// If so, we'll be doing an update.
// Otherwise we'll assume this is an initial render.
if (isRoot(node)) {
update(element, node);
} else {
mount(element, node);
}
}
Like the comment said, we check if it's a root node. If so, we are updating them, instead of mounting from scratch again.
How is the isRoot function implemented? It's quite simple, inside React, we have:
const ROOT_KEY = 'a_unique_key_react_Id';
let rootID = 1;
// Used to track root instances.
const instancesByRootID = {};
and in every mounting process(mount(component, node)), we set
and rootID++ when the mounting ends. They help React keep track of the mounting process.
Update
We already know how mount works. It's just the mapping from a React element to the real DOM instances. In render, however, we also have update when the node has already been rendered once. So it's more cheap. Updating is just re-calculating the props and re-render. Remember the [Reconciliation]() post that we talked about in Day1, about when to update, and when to unmount and re-mount? That's gonna help you understand this part better.
function update(element, node) {
// Find the internal react instance and update it
let id = node.dataset[ROOT_KEY];
let instance = instancesByRootID[id];
if (shouldUpdateComponent(instance, element)) {
// use current instance to update the element
// it's a method in the `Component` class, we'll get back to this in next post
// right now, just know that the instance gets updated with the new props
instance.updateComponent(element)
} else {
// Unmount and then mount the new one
unmountComponentAtNode(node);
mount(element, node);
}
}
function shouldUpdateComponent(instance, element) {
// shortcut beforehand if it's not even the same time any more
return instance.type === element.type
}
function unmountComponentAtNode(node) {
let id = node.dataset[ROOT_KEY];
let instance = instancesByRootID[id];
instance.unmountComponent();
delete instancesByRootID[id];
// Reset the DOM node
node.innerHTML = '';
delete node.dataset[ROOT_KEY];
}
What We've Achieved So Far
We've covered most of the things you need to know with respect to the render part. But in this part you've already seen many important concepts that React uses to build up its whole architecture, and one of them is the react component element tree, and the JSX syntax which is used to create that.
You may notice that currently in the mount function we only support functional component. Because we directly call:
// in mountComposite()
const newNode = component.type(component.props)
What if the component is not a function, but a class instead? And where does the internal state go? What happens when you create a class that extends React.Component? For that we'll discuss in the next post. Please do take some time to stop and review what we've covered so far. No hurry.
Mounting Contd.
You've probably noticed that in the last post we wrote:
which is very similar to what you are doing in React:
Clearly we took a shortcut in the former one. The mounting process is expensive. It's quite like building everything from scratch. We do not want to do that in each render. In react, the real render function looks something like this:
Like the comment said, we check if it's a root node. If so, we are updating them, instead of mounting from scratch again.
How is the
isRoot
function implemented? It's quite simple, inside React, we have:and in every mounting process(
mount(component, node)
), we setand
rootID++
when the mounting ends. They help React keep track of the mounting process.Update
We already know how
mount
works. It's just the mapping from a React element to the real DOM instances. In render, however, we also haveupdate
when the node has already been rendered once. So it's more cheap. Updating is just re-calculating the props and re-render. Remember the [Reconciliation]() post that we talked about in Day1, about when to update, and when to unmount and re-mount? That's gonna help you understand this part better.What We've Achieved So Far
We've covered most of the things you need to know with respect to the
render
part. But in this part you've already seen many important concepts that React uses to build up its whole architecture, and one of them is the react component element tree, and the JSX syntax which is used to create that.You may notice that currently in the
mount
function we only support functional component. Because we directly call:What if the component is not a function, but a class instead? And where does the
internal state
go? What happens when you create a class that extendsReact.Component
? For that we'll discuss in the next post. Please do take some time to stop and review what we've covered so far. No hurry.