wip added hooks and some basic debugging
This commit is contained in:
parent
868305cc63
commit
e12618a688
|
|
@ -4,6 +4,7 @@ import {
|
||||||
EffectTag,
|
EffectTag,
|
||||||
isFunctionFiber,
|
isFunctionFiber,
|
||||||
isHostFiber,
|
isHostFiber,
|
||||||
|
StateHook,
|
||||||
type Child,
|
type Child,
|
||||||
type FiberNode,
|
type FiberNode,
|
||||||
type FunctionFiber,
|
type FunctionFiber,
|
||||||
|
|
@ -90,16 +91,44 @@ 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;
|
||||||
const children = [fiber.type(fiber.pendingProps)];
|
if (fiber.alternate && canBailout(fiber)) {
|
||||||
reconcileChildren(fiber, children);
|
fiber.pendingChildren = fiber.alternate.pendingChildren;
|
||||||
|
} else {
|
||||||
|
fiber.pendingChildren = [fiber.type(fiber.pendingProps)];
|
||||||
|
}
|
||||||
|
reconcileChildren(fiber, fiber.pendingChildren);
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateHostComponent(fiber: HostFiber) {
|
function updateHostComponent(fiber: HostFiber) {
|
||||||
|
|
@ -128,6 +157,26 @@ 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[] = [],
|
||||||
|
|
@ -150,21 +199,9 @@ 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 = {
|
newFiber = createAlternate(oldFiber);
|
||||||
$$typeof: FiberNodeSymbol,
|
newFiber.key = element.key ?? null;
|
||||||
type: oldFiber.type,
|
newFiber.pendingProps = element.props;
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -183,6 +220,8 @@ function reconcileChildren(
|
||||||
effectTag: EffectTag.Placement,
|
effectTag: EffectTag.Placement,
|
||||||
alternate: null,
|
alternate: null,
|
||||||
nextEffect: null,
|
nextEffect: null,
|
||||||
|
actions: null,
|
||||||
|
pendingChildren: [],
|
||||||
};
|
};
|
||||||
pushEffect(newFiber);
|
pushEffect(newFiber);
|
||||||
}
|
}
|
||||||
|
|
@ -394,6 +433,8 @@ 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,
|
||||||
|
|
@ -412,6 +453,8 @@ 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) {
|
||||||
|
|
@ -432,3 +475,20 @@ export function render(rootFiber: RootFiber, element: JSXElement) {
|
||||||
};
|
};
|
||||||
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];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,13 @@
|
||||||
import { createRootFiber, render, scheduleRerender } from "./cr";
|
import { createRootFiber, logFiber, 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];
|
||||||
|
|
@ -15,6 +21,7 @@ const App = () => {
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Hello world {String(++renderCount)}
|
Hello world {String(++renderCount)}
|
||||||
|
<Child />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -42,11 +42,17 @@ 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
|
||||||
|
|
@ -63,12 +69,14 @@ 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 & {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue