Skip to content
This repository has been archived by the owner on Sep 3, 2022. It is now read-only.

Commit

Permalink
Major refactor of patch algo.
Browse files Browse the repository at this point in the history
1. Previously the patch algo returned a vnode which you had to capture and return to the next render.
2. Now patch returns the element base of the component. As such, you capture on the first render only. After that, just render.
3. You do need to pass the component element as the thrid parameter during re-renders, but no re-capture any more.
4. Changes to patch required updates to render, unmount, hydrate, removeElement and updateElement.
5. Updated tests for changes.
  • Loading branch information
Wobbabits committed Oct 9, 2018
1 parent 92971e2 commit 5faaac4
Show file tree
Hide file tree
Showing 10 changed files with 68 additions and 50 deletions.
2 changes: 1 addition & 1 deletion dist/composi.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file modified dist/composi.js.gz
Binary file not shown.
2 changes: 1 addition & 1 deletion dist/composi.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@composi/core",
"version": "0.5.5",
"version": "0.6.0",
"description": "A JavaScript library for creating websites, PWAs and hybrid apps.",
"main": "src/index.js",
"scripts": {
Expand Down
8 changes: 4 additions & 4 deletions src/render.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ import { patch } from './vdom'
* @typedef {import('./vnode').VNode} VNode
* @param {VNode} newVNode
* @param {Element | string} container
* @param {VNode} [oldVNode]
* @return {VNode} VNode
* @param {Element} [element]
* @return {Element} element
*/
export function render(newVNode, container, oldVNode) {
return patch(newVNode, container, oldVNode)
export function render(newVNode, container, element) {
return patch(newVNode, container, element)
}
11 changes: 7 additions & 4 deletions src/unmount.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,23 @@
* unmount(title)
```
* @typedef {import('./vnode').VNode} VNode
* @param {VNode} vnode The virtual node of the component to unmount.
* @param {Element} element The virtual node of the component to unmount.
* @return {void} undefined
*/
export function unmount(vnode) {
export function unmount(element) {
let vnode = element['vnode']
let elem = element
/**
* Function to remove the base element of a functional component from the DOM.
* @return {void} undefined
*/
function doneUnmounting() {
vnode.element.parentNode.removeChild(vnode.element)
vnode.element = null
elem.remove()
return
}
if (vnode.props['onunmount']) {
vnode.props['onunmount'](doneUnmounting, vnode.element)
element= null
} else {
doneUnmounting()
}
Expand Down
34 changes: 21 additions & 13 deletions src/vdom.js
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,11 @@ function removeChildren(node) {
*/
function removeElement(parent, vnode) {
function done() {
if (parent && parent.nodeType) parent.removeChild(removeChildren(vnode))
if (parent && parent.nodeType) try {
parent.removeChild(removeChildren(vnode))
} catch(err) {
console.log(err)
}
}

const cb = vnode.props && vnode.props['onunmount']
Expand Down Expand Up @@ -208,20 +212,20 @@ function updateElement(
isSVG,
isRecycled
) {
let elem = element
for (let prop in mergeObjects(oldProps, newProps)) {
if (
(prop === 'value' || prop === 'checked'
? element[prop]
: oldProps[prop]) !== newProps[prop]
(prop === 'value' || prop === 'checked' ? elem[prop] : oldProps[prop]) !==
newProps[prop]
) {
setProp(element, prop, oldProps[prop], newProps[prop], isSVG)
setProp(elem, prop, oldProps[prop], newProps[prop], isSVG)
}
}

const cb = isRecycled ? newProps['onmount'] : newProps['onupdate']
if (cb != null) {
lifecycle.push(function() {
cb(element, oldProps, newProps)
cb(elem, oldProps, newProps)
})
}
}
Expand All @@ -244,10 +248,11 @@ export function patchElement(
lifecycle,
isSVG
) {
let elem = element
let testSVG = isSVG
let elem = element
// Abort if vnodes are identical.
if (newVNode === oldVNode) {
return
} else if (
oldVNode != null &&
oldVNode.flag === TEXT_NODE &&
Expand Down Expand Up @@ -446,29 +451,32 @@ export class FragmentError {
* Function to either mount an element the first time or patch it in place. This behavior depends on the value of the old VNode. If it is null, a new element will be created, otherwise it compares the new VNode with the old one and patches it.
* @param {VNode} newVNode
* @param {Element | string} container
* @param {VNode} [oldVNode]
* @return {VNode} VNode
* @param {Element} [element]
* @return {Element} element
*/
export function patch(newVNode, container, oldVNode) {
export function patch(newVNode, container, element) {
let cont = container
let elem = element
if (typeof cont === 'string') {
cont = document.querySelector(cont)
}
let oldVNode = elem && elem['vnode']
const lifecycle = []

if (!oldVNode) {
if (Array.isArray(newVNode)) throw new FragmentError()
const el = createElement(newVNode, lifecycle)
cont.appendChild(el)
elem = cont.appendChild(el)
newVNode.element = el
} else {
patchElement(cont, oldVNode['element'], oldVNode, newVNode, lifecycle)
patchElement(cont, elem, oldVNode, newVNode, lifecycle)
}

if (newVNode !== oldVNode) {
while (lifecycle.length > 0) lifecycle.pop()()
}

newVNode.element['isMounted'] = true
return newVNode
elem['vnode'] = newVNode
return elem
}
6 changes: 4 additions & 2 deletions src/vnode.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,19 +56,21 @@ export function createTextVNode(text, element) {
/**
* Create a virtual node represeting an element and its children.
* @param {Element} element
* @return {VNode} VNode
* @return {Element} element
*/
export function hydrate(element) {
let elem = element
if (typeof elem === 'string') elem = document.querySelector(elem)
return createVNode(
const vnode = createVNode(
elem.nodeName.toLowerCase(),
EMPTY_OBJECT,
EMPTY_ARRAY.map.call(elem.childNodes, vnodeFromChild),
elem,
null,
RECYCLED_NODE
)
elem['vnode'] = vnode
return elem
}

/**
Expand Down
Loading

0 comments on commit 5faaac4

Please sign in to comment.