Skip to content

Commit

Permalink
Merge branch 'master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
marvinhagemeister authored Jun 15, 2019
2 parents e8036de + 3e3f3f9 commit 6001f8d
Show file tree
Hide file tree
Showing 10 changed files with 570 additions and 22 deletions.
4 changes: 2 additions & 2 deletions compat/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ options.event = e => {
};

let oldCatchRender = options._catchRender;
options._catchRender = (error, component) => (
oldCatchRender && oldCatchRender(error, component) || catchRender(error, component)
options._catchRender = (error, newVNode, oldVNode) => (
oldCatchRender && oldCatchRender(error, newVNode, oldVNode) || catchRender(error, newVNode, oldVNode)
);

/**
Expand Down
21 changes: 14 additions & 7 deletions compat/src/suspense.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,24 @@ import { removeNode } from '../../src/util';

/**
* @param {any} error
* @param {import('./internal').VNode} vnode
* @param {import('./internal').VNode} newVNode
* @param {import('./internal').VNode} oldVNode
*/
export function catchRender(error, vnode) {
export function catchRender(error, newVNode, oldVNode) {
// thrown Promises are meant to suspend...
if (error.then) {

/** @type {import('./internal').Component} */
let component;
let vnode = newVNode;

for (; vnode; vnode = vnode._parent) {
if ((component = vnode._component) && component._childDidSuspend) {
if (oldVNode) {
newVNode._dom = oldVNode._dom;
newVNode._children = oldVNode._children;
}

component._childDidSuspend(error);
return true;
}
Expand All @@ -27,18 +34,18 @@ function removeDom(children) {
for (let i = 0; i < children.length; i++) {
let child = children[i];
if (child != null) {
if (child._children) {
removeDom(child._children);
}
if (child._dom) {
if (typeof child.type !== 'function' && child._dom) {
removeNode(child._dom);
}
else if (child._children) {
removeDom(child._children);
}
}
}
}

// having custom inheritance instead of a class here saves a lot of bytes
export function Suspense(props) {
export function Suspense() {
// we do not call super here to golf some bytes...
this._suspensions = [];
}
Expand Down
26 changes: 24 additions & 2 deletions src/component.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,16 +61,20 @@ Component.prototype.setState = function(update, callback) {
* re-renderd
*/
Component.prototype.forceUpdate = function(callback) {
let vnode = this._vnode, dom = this._vnode._dom, parentDom = this._parentDom;
let vnode = this._vnode, oldDom = this._vnode._dom, parentDom = this._parentDom;
if (parentDom) {
// Set render mode so that we can differantiate where the render request
// is coming from. We need this because forceUpdate should never call
// shouldComponentUpdate
const force = callback!==false;

let mounts = [];
diff(parentDom, vnode, assign({}, vnode), this._context, parentDom.ownerSVGElement!==undefined, null, mounts, force, dom == null ? getDomSibling(vnode) : dom);
let newDom = diff(parentDom, vnode, assign({}, vnode), this._context, parentDom.ownerSVGElement!==undefined, null, mounts, force, oldDom == null ? getDomSibling(vnode) : oldDom);
commitRoot(mounts, vnode);

if (newDom != oldDom) {
updateParentDomPointers(vnode);
}
}
if (callback) callback();
};
Expand Down Expand Up @@ -118,6 +122,24 @@ export function getDomSibling(vnode, childIndex) {
return typeof vnode.type === 'function' ? getDomSibling(vnode) : null;
}

/**
* @param {import('./internal').VNode} vnode
*/
function updateParentDomPointers(vnode) {
if ((vnode = vnode._parent) != null && vnode._component != null) {
vnode._dom = vnode._component.base = null;
for (let i = 0; i < vnode._children.length; i++) {
let child = vnode._children[i];
if (child != null && child._dom != null) {
vnode._dom = vnode._component.base = child._dom;
break;
}
}

return updateParentDomPointers(vnode);
}
}

/**
* The render queue
* @type {Array<import('./internal').Component>}
Expand Down
9 changes: 8 additions & 1 deletion src/diff/children.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,11 @@ export function diffChildren(parentDom, newParentVNode, oldParentVNode, context,
// have a non-null _lastDomChild. Continue the diff from the end of
// this Fragment's DOM tree.
newDom = childVNode._lastDomChild;

// Eagerly cleanup _lastDomChild. We don't need to persist the value because
// it is only used by `diffChildren` to determine where to resume the diff after
// diffing Components and Fragments.
childVNode._lastDomChild = null;
}
else if (excessDomChildren==oldVNode || newDom!=oldDom || newDom.parentNode==null) {
// NOTE: excessDomChildren==oldVNode above:
Expand All @@ -124,7 +129,9 @@ export function diffChildren(parentDom, newParentVNode, oldParentVNode, context,

if (typeof newParentVNode.type == 'function') {
// At this point, if childVNode._lastDomChild existed, then
// newDom = childVNode._lastDomChild per line 101
// newDom = childVNode._lastDomChild per line 101. Else it is
// the same as childVNode._dom, meaning this component returned
// only a single DOM node
newParentVNode._lastDomChild = newDom;
}
}
Expand Down
3 changes: 1 addition & 2 deletions src/diff/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@ export function diff(parentDom, newVNode, oldVNode, context, isSvg, excessDomChi
c._dirty = false;
c._vnode = newVNode;
newVNode._dom = oldVNode._dom;
newVNode._lastDomChild = oldVNode._lastDomChild;
newVNode._children = oldVNode._children;
break outer;
}
Expand All @@ -116,7 +115,7 @@ export function diff(parentDom, newVNode, oldVNode, context, isSvg, excessDomChi
toChildArray(isTopLevelFragment ? tmp.props.children : tmp, newVNode._children=[], coerceToVNode, true);
}
catch (e) {
if ((tmp = options._catchRender) && tmp(e, newVNode)) return;
if ((tmp = options._catchRender) && tmp(e, newVNode, oldVNode)) break outer;
throw e;
}

Expand Down
4 changes: 2 additions & 2 deletions src/internal.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export interface Options extends preact.Options {
/** Attach a hook that is invoked before a hook's state is queried. */
_hook?(component: Component): void;
/** Attach a hook that is invoked after an error is caught in a component but before calling lifecycle hooks */
catchError?(error: any, vnode: VNode): void;
_catchError?(error: any, vnode: VNode): void;
/**
* Attach a hook that is invoked after an error is caught while executing render.
*
Expand All @@ -23,7 +23,7 @@ export interface Options extends preact.Options {
* @param vnode The VNode whose component's render method threw an error
* @return Return a boolean indicating whether the error was handled by the hook or not
*/
catchRender?(error: any, vnode: VNode): boolean;
_catchRender?(error: any, newVNode: VNode, oldVNode: VNode): boolean;
}

export interface FunctionalComponent<P = {}> extends preact.FunctionComponent<P> {
Expand Down
6 changes: 6 additions & 0 deletions test/_util/dom.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ export const span = contents => `<span>${contents}</span>`;
*/
export const div = contents => `<div>${contents}</div>`;

/**
* A helper to generate innerHTML validation strings containing p
* @param {string | number} contents The contents of the p, as a string
*/
export const p = contents => `<p>${contents}</p>`;

/**
* A helper to generate innerHTML validation strings containing sections
* @param {string | number} contents The contents of the section, as a string
Expand Down
Loading

0 comments on commit 6001f8d

Please sign in to comment.