Skip to content

Commit

Permalink
As per React, exposed hydrate to public. Fixes Github #1270
Browse files Browse the repository at this point in the history
  • Loading branch information
Havunen committed Feb 3, 2018
1 parent f10b8d9 commit 983b89e
Show file tree
Hide file tree
Showing 8 changed files with 76 additions and 27 deletions.
2 changes: 1 addition & 1 deletion fixtures/browser/karma.sauce.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ module.exports = function(config) {
sauceLabs: {
build: 'TRAVIS #' + process.env.TRAVIS_BUILD_NUMBER + ' (' + process.env.TRAVIS_BUILD_ID + ')',
tunnelIdentifier: process.env.TRAVIS_JOB_NUMBER,
startConnect: false,
startConnect: true,
testName: `InfernoJS`,
recordVideo: false,
recordScreenshots: false,
Expand Down
4 changes: 4 additions & 0 deletions packages/inferno-compat/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
createTextVNode,
createVNode,
directClone,
hydrate,
EMPTY_OBJ,
getFlagsForElementVnode,
InfernoChildren,
Expand Down Expand Up @@ -357,6 +358,7 @@ if (isBrowser && typeof (window as any).React === 'undefined') {
findDOMNode,
getFlagsForElementVnode,
getNumberStyleValue,
hydrate,
isValidElement,
linkEvent,
normalizeChildren,
Expand Down Expand Up @@ -402,6 +404,7 @@ export {
findDOMNode,
getFlagsForElementVnode,
getNumberStyleValue,
hydrate,
isValidElement,
linkEvent,
normalizeChildren,
Expand Down Expand Up @@ -436,6 +439,7 @@ export default {
findDOMNode,
getFlagsForElementVnode,
getNumberStyleValue,
hydrate,
isValidElement,
linkEvent,
normalizeChildren,
Expand Down
36 changes: 35 additions & 1 deletion packages/inferno/__tests__/rendering.spec.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Component, createTextVNode, createVNode, render } from 'inferno';
import { Component, createTextVNode, createVNode, render, hydrate } from 'inferno';
import { NO_OP } from 'inferno-shared';
import { ChildFlags, VNodeFlags } from 'inferno-vnode-flags';
import { triggerEvent } from "inferno-utils";

describe('rendering routine', () => {
let container;
Expand Down Expand Up @@ -208,4 +209,37 @@ describe('rendering routine', () => {
expect(container.innerHTML).toEqual('<div><div>Hello 12</div><div>Hello 21</div><div>Hello 12</div></div>');
});
});

// hydrate should be exposed
describe('hydrate', () => {
it('Should be possible to hydrate manually', () => {
// create matching DOM
container.innerHTML = '<input type="checkbox"/>';

let clickChecked = null;
let changeChecked = null;

// Hydrate manually, instead rendering
hydrate(
<input
type="checkbox"
checked={false}
onClick={e => {
clickChecked = e.target.checked;
}}
onChange={e => {
changeChecked = e.target.checked;
}}
/>,
container
);
const input = container.firstChild;

triggerEvent('click', input);

expect(input.checked).toBe(false);
expect(clickChecked).toBe(true);
expect(changeChecked).toBe(true);
});
});
});
25 changes: 15 additions & 10 deletions packages/inferno/src/DOM/hydration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { isFunction, isNull, isNullOrUndef, isString, throwError, warning } from
import { ChildFlags, VNodeFlags } from 'inferno-vnode-flags';
import { VNode } from '../core/implementation';
import { mount, mountClassComponentCallbacks, mountElement, mountFunctionalComponentCallbacks, mountRef, mountText } from './mounting';
import { EMPTY_OBJ, replaceChild } from './utils/common';
import { callAll, EMPTY_OBJ, LIFECYCLE, replaceChild} from './utils/common';
import { createClassComponentInstance, handleComponentInput } from './utils/componentutil';
import { isSamePropsInnerHTML } from './utils/innerhtml';
import { mountProps } from './props';
Expand All @@ -16,13 +16,13 @@ function hydrateComponent(vNode: VNode, dom: Element, lifecycle: Function[], con
const instance = createClassComponentInstance(vNode, type, props, context);
const input = instance.$LI;

hydrate(input, dom, lifecycle, instance.$CX, isSVG);
hydrateVNode(input, dom, lifecycle, instance.$CX, isSVG);
vNode.dom = input.dom;
mountClassComponentCallbacks(vNode, ref, instance, lifecycle);
instance.$UPD = false; // Mount finished allow going sync
} else {
const input = handleComponentInput(type(props, context), vNode);
hydrate(input, dom, lifecycle, context, isSVG);
hydrateVNode(input, dom, lifecycle, context, isSVG);
vNode.children = input;
vNode.dom = input.dom;
mountFunctionalComponentCallbacks(props, ref, dom, lifecycle);
Expand Down Expand Up @@ -77,7 +77,7 @@ function hydrateElement(vNode: VNode, dom: Element, lifecycle: Function[], conte
} else {
const nextSibling = childNode.nextSibling;

hydrate(children as VNode, childNode as Element, lifecycle, context, isSVG);
hydrateVNode(children as VNode, childNode as Element, lifecycle, context, isSVG);
childNode = nextSibling;
}
} else if (childFlags & ChildFlags.MultipleChildren) {
Expand All @@ -88,7 +88,7 @@ function hydrateElement(vNode: VNode, dom: Element, lifecycle: Function[], conte
mount(child as VNode, dom, lifecycle, context, isSVG);
} else {
const nextSibling = childNode.nextSibling;
hydrate(child as VNode, childNode as Element, lifecycle, context, isSVG);
hydrateVNode(child as VNode, childNode as Element, lifecycle, context, isSVG);
childNode = nextSibling;
}
}
Expand Down Expand Up @@ -148,7 +148,7 @@ function hydrateText(vNode: VNode, dom: Element) {
}
}

function hydrate(vNode: VNode, dom: Element, lifecycle: Function[], context: Object, isSVG: boolean) {
function hydrateVNode(vNode: VNode, dom: Element, lifecycle: Function[], context: Object, isSVG: boolean) {
const flags = vNode.flags;

if (flags & VNodeFlags.Component) {
Expand All @@ -167,18 +167,23 @@ function hydrate(vNode: VNode, dom: Element, lifecycle: Function[], context: Obj
}
}

export function hydrateRoot(input, parentDom: Element, lifecycle: Function[]) {
export function hydrate(input, parentDom: Element, callback?: Function) {
let dom = parentDom.firstChild as Element;

if (!isNull(dom)) {
hydrate(input, dom, lifecycle, EMPTY_OBJ, false);
hydrateVNode(input, dom, LIFECYCLE, EMPTY_OBJ, false);
dom = parentDom.firstChild as Element;
// clear any other DOM nodes, there should be only a single entry for the root
while ((dom = dom.nextSibling as Element)) {
parentDom.removeChild(dom);
}
return true;
}

return false;
if (LIFECYCLE.length > 0) {
callAll(LIFECYCLE);
}

if (isFunction(callback)) {
callback();
}
}
22 changes: 13 additions & 9 deletions packages/inferno/src/DOM/rendering.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import { isBrowser, isFunction, isInvalid, isNullOrUndef, isUndefined, NO_OP, throwError, warning } from 'inferno-shared';
import {
isBrowser, isFunction, isInvalid, isNull, isNullOrUndef, isUndefined, NO_OP, throwError,
warning
} from 'inferno-shared';
import { ChildFlags, VNodeFlags} from 'inferno-vnode-flags';
import { createVNode, directClone, InfernoChildren, InfernoInput, options, VNode } from '../core/implementation';
import { hydrateRoot } from './hydration';
import { hydrate } from './hydration';
import { mount } from './mounting';
import { patch } from './patching';
import { remove } from './unmounting';
import { callAll, EMPTY_OBJ } from './utils/common';
import { callAll, EMPTY_OBJ, LIFECYCLE } from './utils/common';

const roots = options.roots;

Expand All @@ -17,7 +20,6 @@ if (process.env.NODE_ENV !== 'production') {
}
}

export const lifecycle: Function[] = [];
const documentBody = isBrowser ? document.body : null;

export function render(input: InfernoInput, parentDom: Element | SVGAElement | DocumentFragment | HTMLElement | Node, callback?: Function): InfernoChildren {
Expand Down Expand Up @@ -46,8 +48,10 @@ export function render(input: InfernoInput, parentDom: Element | SVGAElement | D
if ((input as VNode).dom) {
input = directClone(input as VNode);
}
if (!hydrateRoot(input, parentDom as any, lifecycle)) {
mount(input as VNode, parentDom as Element, lifecycle, EMPTY_OBJ, false);
if (isNull(parentDom.firstChild)) {
mount(input as VNode, parentDom as Element, LIFECYCLE, EMPTY_OBJ, false);
} else {
hydrate(input, parentDom as any)
}
(parentDom as any).$V = input;
roots.push(parentDom);
Expand All @@ -61,13 +65,13 @@ export function render(input: InfernoInput, parentDom: Element | SVGAElement | D
if ((input as VNode).dom) {
input = directClone(input as VNode);
}
patch(rootInput as VNode, input as VNode, parentDom as Element, lifecycle, EMPTY_OBJ, false);
patch(rootInput as VNode, input as VNode, parentDom as Element, LIFECYCLE, EMPTY_OBJ, false);
rootInput = (parentDom as any).$V = input;
}
}

if (lifecycle.length > 0) {
callAll(lifecycle);
if (LIFECYCLE.length > 0) {
callAll(LIFECYCLE);
}

if (isFunction(callback)) {
Expand Down
1 change: 1 addition & 0 deletions packages/inferno/src/DOM/utils/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { svgNS } from '../constants';
// We need EMPTY_OBJ defined in one place.
// Its used for comparison so we cant inline it into shared
export const EMPTY_OBJ = {};
export const LIFECYCLE: Function[] = [];

if (process.env.NODE_ENV !== 'production') {
Object.freeze(EMPTY_OBJ);
Expand Down
11 changes: 5 additions & 6 deletions packages/inferno/src/core/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import { VNodeFlags } from 'inferno-vnode-flags';
import { Props, VNode } from './implementation';
import { combineFrom, isFunction, isNull, isNullOrUndef, throwError } from 'inferno-shared';
import { updateClassComponent } from '../DOM/patching';
import { callAll, EMPTY_OBJ } from '../DOM/utils/common';
import { lifecycle } from "../DOM/rendering";
import { callAll, EMPTY_OBJ, LIFECYCLE } from '../DOM/utils/common';

const resolvedPromise: any = typeof Promise === 'undefined' ? null : Promise.resolve();
const fallbackMethod = typeof requestAnimationFrame === 'undefined' ? setTimeout : requestAnimationFrame;
Expand Down Expand Up @@ -49,7 +48,7 @@ function queueStateChanges<P, S>(component: Component<P, S>, newState: S | Funct
} else {
component.$PSS = true;
if (component.$BR && isFunction(callback)) {
lifecycle.push(callback.bind(component));
LIFECYCLE.push(callback.bind(component));
}
}
}
Expand Down Expand Up @@ -90,7 +89,7 @@ function applyState<P, S>(component: Component<P, S>, force: boolean, callback?:
vNode,
props,
parentDom,
lifecycle as any,
LIFECYCLE,
context,
(vNode.flags & VNodeFlags.SvgElement) > 0,
force,
Expand All @@ -109,8 +108,8 @@ function applyState<P, S>(component: Component<P, S>, force: boolean, callback?:
}
}

if ((lifecycle as any).length > 0) {
callAll(lifecycle as any);
if (LIFECYCLE.length > 0) {
callAll(LIFECYCLE);
}
} else {
component.state = component.$PS as any;
Expand Down
2 changes: 2 additions & 0 deletions packages/inferno/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { createPortal, createRenderer, render } from './DOM/rendering';
import { EMPTY_OBJ } from './DOM/utils/common';
import { Component } from './core/component';
import { getNumberStyleValue } from './DOM/props';
import { hydrate } from "./DOM/hydration";

if (process.env.NODE_ENV !== 'production') {
/* tslint:disable-next-line:no-empty */
Expand Down Expand Up @@ -52,6 +53,7 @@ export {
directClone,
getFlagsForElementVnode,
getNumberStyleValue,
hydrate,
linkEvent,
normalizeChildren,
normalizeProps,
Expand Down

0 comments on commit 983b89e

Please sign in to comment.