Re-rendering a specific node in the DOM when the state changes can be tricky, but it’s not too hard once you understand how it works. And I’m here to walk you through the process, we’ll break down the implementation step by step.
Our Structure
We’ll build on the structure from our last post. Feel free to fork it. Your final result should look like this:
Directorysrc
Directoryutils
jsx-runtime.mjs
render-jsx.mjs
render.mjs
signal.mjs
App.mjs
index.html
index.mjs
.babelrc
package.json
Refactoring the Code
Currently, every time the state changes, the entire page is re-rendered, which affects performance, especially in larger projects. To improve this, we need a solution that compares nodes to find differences between the old and new ones, and updates only the changed nodes.
Let’s get started by adding a new function, renderVNode, to the /src/utils/render-jsx.mjs file. We’ll move all the logic from renderJSX into renderVNode. For now, renderJSX will be empty, but don’t worry, we’ll address that soon.
Your final result should look like this:
Now we need to update renderJSX function to render our virtual DOM nodes.
So, basically, we haven’t changed any behavior yet. This step is just setting us up for future improvements.
Next, we need to update the render function in the /src/utils/render.mjs file.
We’ve removed the renderApp function because it caused the entire page to be re-rendered every time the state changed. This function cleared the page and rebuilt it from them scratch each time.
VirtualDOM Diff
Now, let’s dive into the main part of this update. We’ll create a new diff.mjs file and place it in the /src/utils/ folder.
Directorysrc
Directoryutils
diff.mjs// new file
jsx-runtime.mjs
render-jsx.mjs
render.mjs
signal.mjs
App.mjs
index.html
index.mjs
.babelrc
package.json
We previously added the renderVNode function in the /src/utils/render-jsx.mjs file. Now it’s time to import this function along with any other predefined functions into our new file. It should look like this:
diffProps function
diffProps function is essential in a virtual DOM implementation to efficiently update the actual DOM when a components props change.
Directly manipulating the DOM is slow and can cause performance issues, especially in complex applications. The diffProps function helps avoid unnecessary updates by only modifying the parts of the DOM that have actually changed.
Event listeners need special handling because they are not regular attributes but functions that should be added or removed correctly to ensure that events (like clicks) work as expected.
diffChildren function
The diffChildren function is responsible for comparing the old children of a DOM element with the new children and generating the necessary changes (patches) to update the DOM element.
It manages both updating or removing existing children and adding new ones as needed.
diff function
The diff function is the core part of the virtual DOM diffing algorithm. Its role is to compare two virtual DOM nodes (oldVNode and newVNode) and generate the minimal set of changes (patches) needed to update the real DOM to match the new virtual DOM structure.
It handles the removal, replacement, updating of text nodes, as well as the diffing of properties and children.
renderJSX with diff
And the final step is to apply diff function in renderJSX function.
The renderJSX function is responsible for managing the rendering and updating process of a component represented by a virtual DOM.
Conclusion
We’ve built a VirtualDOM rendering process from the scratch. This approach improves performance by avoiding unnecessary full re-renders, making the rendering process more efficient.