Skip to content

Commit 7dc10a0

Browse files
committed
Added slot checking in render() method for skip unnecessary computation
1 parent 32421f6 commit 7dc10a0

6 files changed

Lines changed: 85 additions & 3 deletions

File tree

docs/rounting.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
The concept of routing is crucial for web application navigation. Traditionally, visiting a website involved making a server request for each click or interaction, leading to the loading of a new HTML page. However, Single-Page Applications (SPAs) have transformed this approach.
2+
3+
SPAs provide a dynamic and interactive user experience by loading a single HTML page initially and updating its content dynamically as users interact. Routing in SPAs refers to how the application manages different views or "pages" based on the URL or user interactions, all without full page reloads. This client-side navigation leads to faster load times, smoother transitions, and a more engaging user experience.

src/components/component.js

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
import { destroyDOM } from "../destroy-dom";
22
import { mountDOM } from "../mount-dom";
33
import { patchDOM } from "../patch-dom";
4-
import { DOM_TYPES, extractChildren } from "../h";
4+
import {
5+
DOM_TYPES,
6+
extractChildren,
7+
didCreateSlot,
8+
resetDidCreateSlot
9+
} from "../h";
510
import { hasOwnProperty } from "../utils/objects";
611
import { Dispatcher } from "../dispatcher";
712
import { fillSlots } from './slots';
813

14+
915
const emptyFn = () => {};
1016

1117
export function defineComponent({ render,
@@ -101,7 +107,11 @@ export function defineComponent({ render,
101107
// returns its view as a virtual DOM based on the state.
102108
// return render.call(this);
103109
const vdom = render.call(this);
104-
fillSlots(vdom, this.#children);
110+
111+
if (didCreateSlot()) {
112+
fillSlots(vdom, this.#children);
113+
resetDidCreateSlot();
114+
}
105115

106116
return vdom;
107117
}

src/h.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ export const DOM_TYPES = {
88
SLOT: 'slot'
99
}
1010

11+
let hSlotCalled = false;
12+
1113
export function hString(str) {
1214
return {
1315
type: DOM_TYPES.TEXT,
@@ -34,7 +36,16 @@ export function hFragment(vNodes) {
3436
}
3537
}
3638

39+
export function didCreateSlot() {
40+
return hSlotCalled;
41+
}
42+
43+
export function resetDidCreateSlot() {
44+
hSlotCalled = false;
45+
}
46+
3747
export function hSlot(children = []) {
48+
hSlotCalled = true;
3849
return { type: DOM_TYPES.SLOT, children };
3950
}
4051

src/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
export { createApp } from './app';
2-
export { hString, hElement, hFragment } from './h';
2+
export { DOM_TYPES, hString, hElement, hFragment, hSlot } from './h';
33
export { defineComponent } from './components/component';
44
export { nextTick } from './next-tick.js'

src/slots.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { traverseDFS } from "./utils/traverse-dom";
2+
import { DOM_TYPES, hFragment } from "./h";
3+
4+
// Replaces the slot nodes with the external content (or their default content).
5+
// You want to traverse the virtual DOM tree and if the encountered node is a slot,
6+
// replace it with the external or default content.
7+
export function fillSlots(vdom, externalContent = []) {
8+
function processNodeFn(node, parent, index) {
9+
insertViewInSlot(node, parent, index, externalContent);
10+
}
11+
12+
traverseDFS(vdom, processNodeFn, shouldSkipBranch);
13+
}
14+
15+
function insertViewInSlot(node, parent, index, externalContent) {
16+
if (node.type !== DOM_TYPES.SLOT) return;
17+
18+
const defaultValue = node.children;
19+
const views = externalContent.length > 0 ? externalContent : defaultValue;
20+
21+
const hasContent = views.length > 0;
22+
if (hasContent) {
23+
parent.children.splice(index, 1, hFragment(views));
24+
} else {
25+
parent.children.splice(index, 1);
26+
}
27+
}
28+
29+
function shouldSkipBranch(node) {
30+
return node.type === DOM_TYPES.COMPONENT;
31+
}
32+
33+
// processNode
34+
// node: the node being processed.
35+
// parent: the parent node of the node being processed.
36+
// index: the index of the node being processed in the parent’s children array.

src/utils/traverse-dom.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
2+
// Explore a node’s children before exploring its siblings. Algorithm 101 :)
3+
4+
export function traverseDFS(
5+
vdom,
6+
processNodeFn,
7+
shouldSkipBranch = () => false,
8+
parentNode = null,
9+
index = null,
10+
) {
11+
if (shouldSkipBranch(vdom)) return;
12+
13+
processNodeFn(vdom, parentNode, index);
14+
15+
if (vdom.children) {
16+
vdom.children.forEach((child, i) =>
17+
traverseDFS(child, processNodeFn, shouldSkipBranch, vdom, i)
18+
)
19+
}
20+
}
21+
22+
// Skip the traversal of a branch of the virtual node tree when a component is encountered.

0 commit comments

Comments
 (0)