How can a page change when someone clicks a button without reloading? The Document Object Model (DOM) is the browser-managed, in-memory tree representing the page’s HTML structure. JavaScript can use the Document API to create elements and change that tree. In a single-page application, a framework does this work to keep the visible page in step with application state. section 3.2 section 1.3.2
You can do the same work without a framework. Start with state, such as an array of to-do descriptions. Use `document.getElementById()` to find the existing input, button, and list. For each description, use `document.createElement()` to make a list item, set its text, and `append()` it to the list. Add event listeners so user actions update both the array and the displayed elements. section 2.2.3
A to-do item makes the main DOM operations concrete:
- Create: build an `li` with a text-bearing `span` and a Done button, then attach click and double-click listeners. section 2.2.3
- Replace: swap the read-mode item for an edit-mode item containing an input and Save and Cancel buttons. section 2.2.3
- Remove or update: change the array, then remove the corresponding node or replace it with a newly rendered one. section 2.2.3
A framework aims to make only the DOM changes needed after state changes. One such change is a patch; updating the view this way is called patching the DOM. Changes can require the browser to reflow and repaint the page, so avoiding unnecessary ones matters. A virtual DOM takes a different role from the actual DOM: it is a lightweight JavaScript tree describing the desired view. Comparing old and new virtual trees can identify changes to apply to the browser’s tree. section 1.3.2 section 3.2 section 7.2.1
Listing 2.4 Rendering the to-dos in read mode (todos.js)
function renderTodoInReadMode(todo) {
const li = document.createElement('li') #1
const span = document.createElement('span') #2
span.textContent = todo
span.addEventListener('dblclick', () => { #3
const idx = todos.indexOf(todo)
todosList.replaceChild( #4
renderTodoInEditMode(todo),
todosList.childNodes[idx]
)
})
li.append(span)
const button = document.createElement('button') #5
button.textContent = 'Done'
button.addEventListener('click', () => { #6
const idx = todos.indexOf(todo)
removeTodo(idx)
})
li.append(button)
return li
}
function removeTodo(index) {
// TODO: implement me!
}
The read-mode renderer shows element creation, text assignment, event listeners, and replacement of a list child in one small function. section 2.2.3
Direct DOM code is enough to build an application, but each state-changing event needs corresponding view-update code. Keeping application logic and DOM manipulation aligned can become verbose. That is the practical problem a rendering framework takes on. section 2.3







