Rendering a list to the DOM and managing its state is a different pair of shoes than managing the state of a simple variable.
Some libraries make use of special identifiers, called keys to enable their after-the-fact rendering engine to figure out what has changed and what needs moving where:
<ul>
{friends.map(friend =>
<li key={friend.id}>
{friend.name}
</li>
)}
</ul>
Another approach that won't involve any guess work is to use an observable collection: a sort of array that when changed, emits an event with detailed information about what elements have changed, so a rendering engine can pick it up and know exactly what's the best way to render the change on the page.
This is what ObservableTypes does, when used with Rimmel.js.
class Item {
// define what your
// items look like here
}
const initial = [ /* initial data */ ];
const data = ObservableCollection(initial, Item);
const addNew = () => {
const newItem = await newItemForm.show();
collection.push(newItem);
}
document.body.innerHTML = rml`
<ul>
${data}
</ul>
<button onclick="${addNew}">
add new
</button>
`;
An observable collection comes with clever proxies for all array methods such as .push()
, .shift()
, .unshift()
, .pop()
, .splice()
, so whenever you call data.push(item)
, the CollectionSink in Rimmel knows that a new item needs appending to the end of the list.
If you call .unshift()
, it knows a new item needs inserting right at the beginning, and so on.
Want to replace the entire content of the collection? The .assign()
method will just do that, and cause the rendering engine to simply replace the whole list in the DOM.
Similarly, all other mutating actions on the collection emit information to the sink such that it will know exactly what sort of DOM mutation to perform to reflect the changes. No guesswork, no overengineered DOM diff, really light and fast code overall.
If you want to check yourself how easy it is to use ObservableTypes, try them in action:
Top comments (0)