UNPKG

2.39 kBJavaScriptView Raw
1import { EMPTY_OBJ, EMPTY_ARR } from './constants';
2import { commitRoot, diff } from './diff/index';
3import { createElement, Fragment } from './create-element';
4import options from './options';
5
6const IS_HYDRATE = EMPTY_OBJ;
7
8/**
9 * Render a Preact virtual node into a DOM element
10 * @param {import('./index').ComponentChild} vnode The virtual node to render
11 * @param {import('./internal').PreactElement} parentDom The DOM element to
12 * render into
13 * @param {Element | Text} [replaceNode] Optional: Attempt to re-use an
14 * existing DOM tree rooted at `replaceNode`
15 */
16export function render(vnode, parentDom, replaceNode) {
17 if (options._root) options._root(vnode, parentDom);
18
19 // We abuse the `replaceNode` parameter in `hydrate()` to signal if we
20 // are in hydration mode or not by passing `IS_HYDRATE` instead of a
21 // DOM element.
22 let isHydrating = replaceNode === IS_HYDRATE;
23
24 // To be able to support calling `render()` multiple times on the same
25 // DOM node, we need to obtain a reference to the previous tree. We do
26 // this by assigning a new `_children` property to DOM nodes which points
27 // to the last rendered tree. By default this property is not present, which
28 // means that we are mounting a new tree for the first time.
29 let oldVNode = isHydrating
30 ? null
31 : (replaceNode && replaceNode._children) || parentDom._children;
32 vnode = createElement(Fragment, null, [vnode]);
33
34 // List of effects that need to be called after diffing.
35 let commitQueue = [];
36 diff(
37 parentDom,
38 // Determine the new vnode tree and store it on the DOM element on
39 // our custom `_children` property.
40 ((isHydrating ? parentDom : replaceNode || parentDom)._children = vnode),
41 oldVNode || EMPTY_OBJ,
42 EMPTY_OBJ,
43 parentDom.ownerSVGElement !== undefined,
44 replaceNode && !isHydrating
45 ? [replaceNode]
46 : oldVNode
47 ? null
48 : parentDom.childNodes.length
49 ? EMPTY_ARR.slice.call(parentDom.childNodes)
50 : null,
51 commitQueue,
52 replaceNode || EMPTY_OBJ,
53 isHydrating
54 );
55
56 // Flush all queued effects
57 commitRoot(commitQueue, vnode);
58}
59
60/**
61 * Update an existing DOM element with data from a Preact virtual node
62 * @param {import('./index').ComponentChild} vnode The virtual node to render
63 * @param {import('./internal').PreactElement} parentDom The DOM element to
64 * update
65 */
66export function hydrate(vnode, parentDom) {
67 render(vnode, parentDom, IS_HYDRATE);
68}