Compare commits

..

No commits in common. "e12618a688905b7ae9394fb80625aa6a2d414028" and "ac413285bffc88cebf0bd2d68fb19b754d00643d" have entirely different histories.

3 changed files with 22 additions and 93 deletions

View File

@ -4,7 +4,6 @@ import {
EffectTag, EffectTag,
isFunctionFiber, isFunctionFiber,
isHostFiber, isHostFiber,
StateHook,
type Child, type Child,
type FiberNode, type FiberNode,
type FunctionFiber, type FunctionFiber,
@ -91,44 +90,16 @@ function createFiberFromElement(element: JSXElement): FiberNode {
effectTag: EffectTag.NoEffect, effectTag: EffectTag.NoEffect,
alternate: null, alternate: null,
nextEffect: null, nextEffect: null,
actions: null,
pendingChildren: [],
}; };
} }
function canBailout(fiber: FiberNode) {
const alternate = fiber.alternate;
if (!alternate) {
return false;
}
if (fiber.actions) {
return false;
}
const propKeys = Object.keys(fiber.pendingProps);
const pendingPropKeys = Object.keys(alternate.pendingProps);
if (propKeys.length !== pendingPropKeys.length) {
return false;
}
if (
propKeys.some(
(key) => fiber.pendingProps[key] !== alternate.pendingProps[key],
)
)
return false;
return true;
}
function updateFunctionComponent(fiber: FunctionFiber) { function updateFunctionComponent(fiber: FunctionFiber) {
wipFiber = fiber; wipFiber = fiber;
hookIndex = 0; hookIndex = 0;
wipFiber.hooks = []; wipFiber.hooks = [];
wipFiber.effectTag = EffectTag.NoEffect; wipFiber.effectTag = EffectTag.NoEffect;
if (fiber.alternate && canBailout(fiber)) { const children = [fiber.type(fiber.pendingProps)];
fiber.pendingChildren = fiber.alternate.pendingChildren; reconcileChildren(fiber, children);
} else {
fiber.pendingChildren = [fiber.type(fiber.pendingProps)];
}
reconcileChildren(fiber, fiber.pendingChildren);
} }
function updateHostComponent(fiber: HostFiber) { function updateHostComponent(fiber: HostFiber) {
@ -157,26 +128,6 @@ function pushEffect(fiber: FiberNode) {
wipRoot.lastEffect = fiber; wipRoot.lastEffect = fiber;
} }
function createAlternate(oldFiber: FiberNode): FiberNode {
return {
$$typeof: FiberNodeSymbol,
type: oldFiber.type,
key: null,
child: null,
sibling: null,
parent: wipFiber,
index: 0,
dom: oldFiber.dom,
hooks: [],
pendingProps: oldFiber.pendingProps,
effectTag: EffectTag.Update,
alternate: oldFiber,
nextEffect: null,
actions: null,
pendingChildren: [],
};
}
function reconcileChildren( function reconcileChildren(
wipFiber: FiberNode | RootFiber, wipFiber: FiberNode | RootFiber,
children: Child[] = [], children: Child[] = [],
@ -199,9 +150,21 @@ function reconcileChildren(
const isSameType = oldFiber && element && element.type === oldFiber.type; const isSameType = oldFiber && element && element.type === oldFiber.type;
if (isSameType && oldFiber) { if (isSameType && oldFiber) {
newFiber = createAlternate(oldFiber); newFiber = {
newFiber.key = element.key ?? null; $$typeof: FiberNodeSymbol,
newFiber.pendingProps = element.props; type: oldFiber.type,
key: element.key ?? null,
child: null,
sibling: null,
parent: wipFiber,
index: 0,
dom: oldFiber.dom,
hooks: [],
pendingProps: element.props,
effectTag: EffectTag.Update,
alternate: oldFiber,
nextEffect: null,
};
pushEffect(newFiber); pushEffect(newFiber);
} }
@ -220,8 +183,6 @@ function reconcileChildren(
effectTag: EffectTag.Placement, effectTag: EffectTag.Placement,
alternate: null, alternate: null,
nextEffect: null, nextEffect: null,
actions: null,
pendingChildren: [],
}; };
pushEffect(newFiber); pushEffect(newFiber);
} }
@ -433,8 +394,6 @@ export function createRootFiber(root: HTMLElement): RootFiber {
isRoot: true, isRoot: true,
firstEffect: null, firstEffect: null,
lastEffect: null, lastEffect: null,
actions: null,
pendingChildren: [],
}; };
const rootFiber: RootFiber = { const rootFiber: RootFiber = {
$$typeof: FiberNodeSymbol, $$typeof: FiberNodeSymbol,
@ -453,8 +412,6 @@ export function createRootFiber(root: HTMLElement): RootFiber {
isRoot: true, isRoot: true,
firstEffect: null, firstEffect: null,
lastEffect: null, lastEffect: null,
actions: null,
pendingChildren: [],
}; };
alternate.alternate = rootFiber; alternate.alternate = rootFiber;
for (const event of events) { for (const event of events) {
@ -473,22 +430,9 @@ export function render(rootFiber: RootFiber, element: JSXElement) {
rootFiber.alternate!.pendingProps = { rootFiber.alternate!.pendingProps = {
children: [element], children: [element],
}; };
// const fiber = createFiberFromElement(element);
// fiber.parent = rootFiber;
// rootFiber.child = fiber;
// wipRoot.child = fiber;
unitOfWork = wipRoot; unitOfWork = wipRoot;
} }
export function logFiber(label: string) {
console.log(label, unitOfWork);
}
export function useState<T>(initialValue: T) {
if (!unitOfWork)
throw new Error("useState can only be used inside of a component!");
const fiber = unitOfWork;
const alternate = fiber.alternate?.hooks[hookIndex];
if (alternate && alternate.type !== StateHook)
throw new Error("Hook order changed smth.");
const value: T = alternate ? alternate.value : initialValue;
const setValue = (newValue: T) => {
fiber.hooks[hookIndex];
};
}

View File

@ -1,13 +1,7 @@
import { createRootFiber, logFiber, render, scheduleRerender } from "./cr"; import { createRootFiber, render, scheduleRerender } from "./cr";
import { domFiber } from "./symbols"; import { domFiber } from "./symbols";
let renderCount = 0; let renderCount = 0;
const Child = () => {
logFiber("Child");
return <div>Child</div>;
};
const App = () => { const App = () => {
console.log("render"); console.log("render");
const items = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; const items = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
@ -21,7 +15,6 @@ const App = () => {
}} }}
> >
Hello world {String(++renderCount)} Hello world {String(++renderCount)}
<Child />
</div> </div>
); );
}; };

View File

@ -42,17 +42,11 @@ export const EffectHook = Symbol.for("cr.effect-hook");
type Hook = type Hook =
| { | {
type: typeof StateHook; type: typeof StateHook;
value: any;
} }
| { | {
type: typeof EffectHook; type: typeof EffectHook;
}; };
type Action = {
execute: (fiber: FiberNode) => void;
nextAction: null | Action;
};
export interface FiberNode { export interface FiberNode {
$$typeof: typeof FiberNodeSymbol; $$typeof: typeof FiberNodeSymbol;
// Identity // Identity
@ -69,14 +63,12 @@ export interface FiberNode {
dom: Node | null; dom: Node | null;
hooks: Hook[]; hooks: Hook[];
pendingProps: any; pendingProps: any;
pendingChildren: Child[];
effectTag: EffectTag; effectTag: EffectTag;
// Used for double buffering // Used for double buffering
alternate: FiberNode | null; alternate: FiberNode | null;
nextEffect: FiberNode | null; nextEffect: FiberNode | null;
actions: Action | null;
} }
export type FunctionFiber = FiberNode & { export type FunctionFiber = FiberNode & {