Skip to content

Commit

Permalink
refactor(tiny-react): remove redundant BNode.parent (#167)
Browse files Browse the repository at this point in the history
  • Loading branch information
hi-ogawa authored Oct 17, 2023
1 parent 736e5d1 commit e045826
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 47 deletions.
4 changes: 2 additions & 2 deletions packages/tiny-react/src/compat/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useEffect, useRef, useState } from "../hooks";
import { render } from "../reconciler";
import { type BNode, EMPTY_VNODE, type FC, type VNode } from "../virtual-dom";
import { type BNode, EMPTY_NODE, type FC, type VNode } from "../virtual-dom";

// non comprehensive compatibility features

Expand Down Expand Up @@ -33,7 +33,7 @@ export function createRoot(container: Element) {
bnode = render(vnode, container, bnode);
},
unmount() {
render(EMPTY_VNODE, container, bnode);
render(EMPTY_NODE, container, bnode);
},
};
}
Expand Down
4 changes: 2 additions & 2 deletions packages/tiny-react/src/helper/hyperscript.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {
EMPTY_VNODE,
EMPTY_NODE,
NODE_TYPE_CUSTOM,
NODE_TYPE_FRAGMENT,
NODE_TYPE_TAG,
Expand Down Expand Up @@ -80,7 +80,7 @@ function normalizeComponentChild(child: ComponentChild): VNode {
typeof child === "undefined" ||
typeof child === "boolean"
) {
return EMPTY_VNODE;
return EMPTY_NODE;
}
if (typeof child === "string" || typeof child === "number") {
return {
Expand Down
10 changes: 0 additions & 10 deletions packages/tiny-react/src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ describe(render, () => {
"children": [
{
"hnode": hello,
"parent": [Circular],
"type": "text",
"vnode": {
"data": "hello",
Expand All @@ -53,7 +52,6 @@ describe(render, () => {
{
"child": {
"hnode": world,
"parent": [Circular],
"type": "text",
"vnode": {
"data": "world",
Expand All @@ -66,7 +64,6 @@ describe(render, () => {
world
</span>,
"listeners": Map {},
"parent": [Circular],
"type": "tag",
"vnode": {
"child": {
Expand Down Expand Up @@ -124,7 +121,6 @@ describe(render, () => {
</span>
</div>,
"listeners": Map {},
"parent": undefined,
"type": "tag",
"vnode": {
"child": {
Expand Down Expand Up @@ -174,7 +170,6 @@ describe(render, () => {
{
"child": {
"hnode": reconcile,
"parent": [Circular],
"type": "text",
"vnode": {
"data": "reconcile",
Expand All @@ -187,7 +182,6 @@ describe(render, () => {
reconcile
</div>,
"listeners": Map {},
"parent": undefined,
"type": "tag",
"vnode": {
"child": {
Expand Down Expand Up @@ -232,7 +226,6 @@ describe(render, () => {
{
"child": {
"hnode": hello,
"parent": [Circular],
"type": "text",
"vnode": {
"data": "hello",
Expand All @@ -243,7 +236,6 @@ describe(render, () => {
hello
</span>,
"listeners": Map {},
"parent": [Circular],
"type": "tag",
"vnode": {
"child": {
Expand All @@ -259,7 +251,6 @@ describe(render, () => {
},
{
"hnode": world,
"parent": [Circular],
"type": "text",
"vnode": {
"data": "world",
Expand Down Expand Up @@ -298,7 +289,6 @@ describe(render, () => {
world
</div>,
"listeners": Map {},
"parent": [Circular],
"type": "tag",
"vnode": {
"child": {
Expand Down
28 changes: 14 additions & 14 deletions packages/tiny-react/src/reconciler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
type BNode,
type BTag,
type BText,
EMPTY_NODE,
type HNode,
NODE_TYPE_CUSTOM,
NODE_TYPE_EMPTY,
Expand All @@ -16,17 +17,18 @@ import {
type Props,
type VCustom,
type VNode,
emptyBNode,
getBNodeKey,
getBNodeParent,
getBNodeSlot,
getVNodeKey,
setBNodeParent,
} from "./virtual-dom";

export function render(vnode: VNode, parent: HNode, bnode?: BNode) {
const effectManager = new EffectManager();
const newBnode = reconcileNode(
vnode,
bnode ?? emptyBNode(),
bnode ?? EMPTY_NODE,
parent,
undefined,
effectManager
Expand All @@ -47,7 +49,7 @@ function reconcileNode(
if (bnode.type === NODE_TYPE_EMPTY) {
} else {
unmount(bnode);
bnode = emptyBNode();
bnode = EMPTY_NODE;
}
} else if (vnode.type === NODE_TYPE_TAG) {
if (
Expand All @@ -71,7 +73,7 @@ function reconcileNode(
const hnode = document.createElement(vnode.name);
const child = reconcileNode(
vnode.child,
emptyBNode(),
EMPTY_NODE,
hnode,
undefined,
effectManager
Expand All @@ -82,13 +84,12 @@ function reconcileNode(
child,
hnode,
listeners: new Map(),
parent: undefined,
} satisfies BTag;
reconcileTagProps(bnode, vnode.props, {});
placeChild(bnode.hnode, hparent, preSlot, true);
effectManager.refNodes.push(bnode);
}
bnode.child.parent = bnode;
setBNodeParent(bnode.child, bnode);
} else if (vnode.type === NODE_TYPE_TEXT) {
if (bnode.type === NODE_TYPE_TEXT) {
if (bnode.vnode.data !== vnode.data) {
Expand All @@ -103,7 +104,6 @@ function reconcileNode(
type: vnode.type,
vnode,
hnode,
parent: undefined,
} satisfies BText;
placeChild(bnode.hnode, hparent, preSlot, true);
}
Expand Down Expand Up @@ -142,15 +142,15 @@ function reconcileNode(
for (let i = 0; i < vnode.children.length; i++) {
const bchild = reconcileNode(
vnode.children[i],
bchildren[i] ?? emptyBNode(),
bchildren[i] ?? EMPTY_NODE,
hparent,
preSlot,
effectManager
);
preSlot = getBNodeSlot(bchild) ?? preSlot;
bnode.slot = getBNodeSlot(bchild) ?? bnode.slot;
bnode.children[i] = bchild;
bchild.parent = bnode;
setBNodeParent(bchild, bnode);
}
} else if (vnode.type === NODE_TYPE_CUSTOM) {
if (
Expand All @@ -174,7 +174,7 @@ function reconcileNode(
const vchild = hookContext.wrap(() => vnode.render(vnode.props));
const child = reconcileNode(
vchild,
emptyBNode(),
EMPTY_NODE,
hparent,
preSlot,
effectManager
Expand All @@ -190,7 +190,7 @@ function reconcileNode(
} satisfies BCustom;
}
bnode.hparent = hparent;
bnode.child.parent = bnode;
setBNodeParent(bnode.child, bnode);
bnode.slot = getBNodeSlot(bnode.child);
effectManager.effectNodes.push(bnode);

Expand Down Expand Up @@ -256,7 +256,7 @@ export function updateCustomNode(vnode: VCustom, bnode: BCustom) {
}

function findPreviousSlot(child: BNode): HNode | undefined {
let parent = child.parent;
let parent = getBNodeParent(child);
while (parent) {
if (parent.type === NODE_TYPE_TAG) {
// no slot i.e. new node will be the first child within parent tag
Expand Down Expand Up @@ -287,7 +287,7 @@ function findPreviousSlot(child: BNode): HNode | undefined {
}

function updateParentSlot(child: BNode) {
let parent = child.parent;
let parent = getBNodeParent(child);
while (parent) {
if (parent.type === NODE_TYPE_TAG) {
return;
Expand Down Expand Up @@ -326,7 +326,7 @@ function alignChildrenByKey(
return [bnodes, []];
}

const newBnodes: BNode[] = vnodes.map(() => emptyBNode());
const newBnodes: BNode[] = vnodes.map(() => EMPTY_NODE);
const oldBnodes: BNode[] = [];

for (const bnode of bnodes) {
Expand Down
35 changes: 16 additions & 19 deletions packages/tiny-react/src/virtual-dom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,17 +70,11 @@ export type BNode = BEmpty | BTag | BText | BCustom | BFragment;

export type BNodeParent = BTag | BCustom | BFragment;

export type BEmpty = {
type: typeof NODE_TYPE_EMPTY;
// not needed since only we need to traverse up only from BCustom?
// but for now, make it easier by having uniform `BNode.parent` type
parent?: BNodeParent;
};
export type BEmpty = VEmpty;

export type BTag = {
type: typeof NODE_TYPE_TAG;
vnode: VTag;
parent?: BNodeParent;
child: BNode;
hnode: HTag;
listeners: Map<string, () => void>;
Expand All @@ -89,7 +83,6 @@ export type BTag = {
export type BText = {
type: typeof NODE_TYPE_TEXT;
vnode: VText;
parent?: BNodeParent;
hnode: HText;
};

Expand All @@ -111,17 +104,7 @@ export type BFragment = {
slot?: HNode;
};

export function emptyBNode(): BEmpty {
return {
type: NODE_TYPE_EMPTY,
parent: undefined,
};
}

// TODO: identical empty vnode?
// for now, this would be critical to not break `memo(Component)` shallow equal with empty children.
// ideally, we could VNode to accomodate `null | string | number` primitives...
export const EMPTY_VNODE: VEmpty = {
export const EMPTY_NODE: VEmpty = {
type: NODE_TYPE_EMPTY,
};

Expand Down Expand Up @@ -157,3 +140,17 @@ export function getBNodeSlot(node: BNode): HNode | undefined {
}
return node.slot;
}

// bnode parent traversal is only for BCustom and BFragment
export function getBNodeParent(node: BNode): BNodeParent | undefined {
if (node.type === NODE_TYPE_CUSTOM || node.type === NODE_TYPE_FRAGMENT) {
return node.parent;
}
return;
}

export function setBNodeParent(node: BNode, parent: BNodeParent) {
if (node.type === NODE_TYPE_CUSTOM || node.type === NODE_TYPE_FRAGMENT) {
node.parent = parent;
}
}

0 comments on commit e045826

Please sign in to comment.