React from First Principles (P1) - Abstraction of the DOM
Document Object Model (DOM) & Mental model shift from imperative to declarative programming using React.

I still remember when I first learned React, I couldn’t wrap my head around this popular frontend library. The only thing I knew was that it’s a powerful library for defining the UIs by creating many components, and that everyone was using it, so maybe I should use it too :) It was not until I encountered many errors that I couldn’t understand that I realized it was time to take a step back and learn what was happening under the hood. To start off 2026, I want to develop an in-depth review series of React. This post is about abstraction. As with any new technology, a higher level of abstraction is introduced over some low-level implementations, which requires a completely different mental model shift, which leads to the question:
Why does React exist in the first place?
To answer this question, let’s take a step back and learn about how the web is built. Before React, the web was traditionally built using static HTML. As the web grew, server-side rendering (SSR) enabled HTML to be created based on the user’s request. Then there came JavaScript, which makes interactivity on the web possible, and the introduction of AJAX, which allows for the partial update of the UI without a full page load. Later, jQuery and MVC frameworks such as Angular emerged, all of which were created to overcome the challenges of direct DOM manipulation and cross-browser differences.

Abstraction
The last part is key. React was also created as a new level of abstraction, to quote its legacy documentation:
[…] abstract out the attribute manipulation, event handling, and manual DOM updating that you would otherwise have to use to build your app.” 1
The DOM, or Document Object Model, represents the document (e.g., HTML document) as a logical tree structure. The tree consists of objects/nodes, each of which contains properties and methods that allow developers to programmatically change the structure, content, or style of the web page.
Before React, to update the interface, we needed to define a script to manipulate the DOM directly. It’s called imperative programming because we have to specify the how. For example, if you want to add a new todo item to your todo list, you need a JavaScript script that includes all the steps required to make the addition
Select the correct elements
Create a function to change the text content based on the user’s input
Add a new element inside the parent element when the button is clicked, using an event listener.
Mental Model Shift: Imperative → Declarative
Basically, when there is a change in the state of a component(s), React will create a tree of React elements via the method render(). This tree is a virtual DOM. It’s virtual because it’s not the actual DOM but a representation of what the UI should look like.
React does not make the change immediately after a change in the state occurs. Instead, it compares the newly created virtual tree with the previous one using a process called reconciliation. Based on this comparison, React determines the minimal set of changes needed and efficiently applies those updates to the actual DOM, rather than re-rendering the entire page.
Todo List Example: Plain JS vs. React
I wrote a tutorial to compare a to-do list written in plain HTML/JavaScript versus one written in React. This is a work in progress as I’m trying to make a strong case for why React is actually preferable than direct DOM manipulation, because if your web application is small and simple, React is unnecessary.
Using plain JavaScript, I had to select all the relevant elements, create new ones, and define what would happen when the button was clicked. In React, instead of specifying all the selection, creation, and event triggers, I describe what the UI would look like if I add a new todo item to the list.
It requires a completely different mental model when using React, as it is based on a component-based and parent-child hierarchy that defines data flow. As a result, in terms of implementation, React appears to be more “complicated” than plainJS because you have to set up the relationship and learn how to describe what you want the UI to look like instead of defining the logic for updating the UI manually. However, I can see how it’s easier to maintain and debug as the application grows more complex, given the project’s modular structure. This means that if you make the hierarchy clear (i.e., which component is the child, which is higher up in the tree, etc.), you can trace back the error more easily.
Meanwhile, I can potentially see how it will get more challenging to maintain and modify as elements become more complex and nested within each other (interdependent) if we do direct DOM manipulation.





