Supporting the key-prop
This commit is contained in:
parent
51f894c616
commit
5704b72542
@ -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?)
|
* @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
|
* This exists as a very basic example/test for JSX-to-DOM
|
||||||
* @category VDOM
|
* @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)
|
// Only items with a renderer are tracked (any other are undefined or null and shoulnd't be rendered at all)
|
||||||
let childType = meta.normedType;
|
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)
|
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] = vChildren[childType] || []; // Make sure the array exists
|
||||||
vChildren[childType].push({
|
vChildren[childType].push({
|
||||||
item: {
|
item: {
|
||||||
@ -142,13 +131,17 @@ export function render(vnode, opts = {}) {
|
|||||||
curElement = curElement.nextSibling;
|
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] = oldVChildren[childType] || []; // Make sure the array exists
|
||||||
oldVChildren[childType].push({
|
let oldItem = {
|
||||||
vnode: next,
|
vnode: next,
|
||||||
element: childElement,
|
element: childElement,
|
||||||
meta: meta
|
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 sortedChildTypes = Array.from(childTypes).sort((a,b)=>a==='node'?1:-1); // Always do ChildNode-types last
|
||||||
let queuedItems = [];
|
let queuedItems = [];
|
||||||
let previous = null;
|
/**@type {VRenderQueueItem}*/ let previous = null;
|
||||||
for(let childType of sortedChildTypes){
|
for(let childType of sortedChildTypes){
|
||||||
let newChildren = vChildren[childType];
|
let newChildren = vChildren[childType];
|
||||||
let oldChildren = oldVChildren[childType];
|
let oldChildren = oldVChildren[childType];
|
||||||
|
|
||||||
while(newChildren && newChildren.length){
|
while(newChildren && newChildren.length){
|
||||||
let child = newChildren.splice(0,1)[0];
|
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;
|
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
|
// Update old-child
|
||||||
child.item.host = oldChild.element;
|
child.item.host = oldChild.element;
|
||||||
child.item.old = oldChild.vnode;
|
child.item.old = oldChild.vnode;
|
||||||
|
|||||||
@ -24,6 +24,15 @@ import "./vnode";
|
|||||||
* @property {VRenderItem} previous - The item that will have been inserted before this one
|
* @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
|
* Global rendering-state when rendering a tree of VNodes
|
||||||
@ -32,5 +41,5 @@ import "./vnode";
|
|||||||
* @category VDOM.renderer
|
* @category VDOM.renderer
|
||||||
* @property {Array.<VRenderQueueItem>} queue - The queue of items to be rendered
|
* @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 {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
|
||||||
**/
|
**/
|
||||||
|
|||||||
@ -25,6 +25,7 @@ export class MyTodo extends CustomElement{
|
|||||||
>
|
>
|
||||||
{this.todos.map(item =>
|
{this.todos.map(item =>
|
||||||
<todo-item
|
<todo-item
|
||||||
|
key={item.id}
|
||||||
model={ item.id }
|
model={ item.id }
|
||||||
checked={ item.checked }
|
checked={ item.checked }
|
||||||
>
|
>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user