Supporting the key-prop

This commit is contained in:
Miel Truyen 2019-11-09 00:50:32 +01:00
parent 51f894c616
commit 5704b72542
4 changed files with 49 additions and 21 deletions

View File

@ -26,17 +26,6 @@ export function getNodeMeta(vnode){
* @property {Element} [parent] - The parent element (TODO not sure what this will do when specified; Insert it as child element of the parent where?)
*/
/**
* Temporary data structure for listing an old VNode
* @typedef VOldQueueItem
* @interface
* @category VDOM.renderer
* @property {VNode} vnode - The old vnode
* @property {VRenderQueueItemMetadata} meta - Meta data for the item such as normedType and the renderer to use(from a preprocessing stage)
* @property {Element} element - The matching element
**/
/**
* This exists as a very basic example/test for JSX-to-DOM
* @category VDOM
@ -103,7 +92,7 @@ export function render(vnode, opts = {}) {
// Only items with a renderer are tracked (any other are undefined or null and shoulnd't be rendered at all)
let childType = meta.normedType;
if(!meta.renderer.remove) childType = 'node'; // Treat anything that doesnt have a special remove-function as ChildNode-type (e.g. it shows up in Element.childNodes)
childTypes.add(childType);// Tract that children of this type exist and should be iterated later
childTypes.add(childType);// Track that children of this type exist and should be iterated later
vChildren[childType] = vChildren[childType] || []; // Make sure the array exists
vChildren[childType].push({
item: {
@ -142,13 +131,17 @@ export function render(vnode, opts = {}) {
curElement = curElement.nextSibling;
}
}
childTypes.add(childType);// Tract that children of this type exist and should be iterated later
childTypes.add(childType);// Track that children of this type exist and should be iterated later
oldVChildren[childType] = oldVChildren[childType] || []; // Make sure the array exists
oldVChildren[childType].push({
let oldItem = {
vnode: next,
element: childElement,
meta: meta
});
};
oldVChildren[childType].push(oldItem);
if(next.props?.key){
state.keyedElements.set(next.key,oldItem);
}
}
}
}
@ -156,17 +149,42 @@ export function render(vnode, opts = {}) {
let sortedChildTypes = Array.from(childTypes).sort((a,b)=>a==='node'?1:-1); // Always do ChildNode-types last
let queuedItems = [];
let previous = null;
/**@type {VRenderQueueItem}*/ let previous = null;
for(let childType of sortedChildTypes){
let newChildren = vChildren[childType];
let oldChildren = oldVChildren[childType];
while(newChildren && newChildren.length){
let child = newChildren.splice(0,1)[0];
let oldChild = oldChildren && oldChildren.splice(0,1)[0];
// Key handling
let childKey = child.item.vnode.props?.key;
/**@type {VOldQueueItem}*/ let oldChild;
if(childKey){
oldChild = state.keyedElements.get(childKey);
if(oldChild) {
if (oldChildren && oldChildren[ 0 ] === oldChild) {
// Old keyed child already in the right place (just clear it from the queue);
oldChildren.splice(0, 1);
} else {
// Old keyed child not already in the right place
let indexOfKeyed = oldChildren.indexOf(oldChild);
if(indexOfKeyed) {
oldChildren.splice(indexOfKeyed, 1);
item.host.removeChild(oldChild.element);
}
if (previous) {
previous.item.host.after(oldChild.element);
} else {
item.parent.prepend(oldChild.element);
}
}
}
}
if(!oldChild) oldChild = oldChildren && oldChildren.splice(0,1)[0];
child.previous = previous;
if(oldChild && child.meta.normedType === oldChild.meta.normedType){
if(oldChild && child.meta.normedType === oldChild.meta.normedType && childKey===oldChild.vnode.props?.key){
// Update old-child
child.item.host = oldChild.element;
child.item.old = oldChild.vnode;

View File

@ -70,7 +70,7 @@ export const NodeTreeRenderer = {
propDiffs.push([key,newVal, undefined]);
}
}
// Now apply each
for(let [key, newVal, oldVal] of propDiffs){
if(VNODEPROP_IGNORE[key]){

View File

@ -24,6 +24,15 @@ import "./vnode";
* @property {VRenderItem} previous - The item that will have been inserted before this one
**/
/**
* Temporary data structure for listing an old VNode
* @typedef VOldQueueItem
* @interface
* @category VDOM.renderer
* @property {VNode} vnode - The old vnode
* @property {VRenderQueueItemMetadata} meta - Meta data for the item such as normedType and the renderer to use(from a preprocessing stage)
* @property {Element} element - The matching element
**/
/**
* Global rendering-state when rendering a tree of VNodes
@ -32,5 +41,5 @@ import "./vnode";
* @category VDOM.renderer
* @property {Array.<VRenderQueueItem>} queue - The queue of items to be rendered
* @property {Array.<[Function,Element]>} refs - Ref-callback functions be called when rendering is done
* @property {Map.<string, VNode>} keyedElements - A map of keyed elements (TODO this needs refining)
* @property {Map.<string, VOldQueueItem>} keyedElements - A map of (old) keyed elements
**/

View File

@ -25,6 +25,7 @@ export class MyTodo extends CustomElement{
>
{this.todos.map(item =>
<todo-item
key={item.id}
model={ item.id }
checked={ item.checked }
>