wip added hooks and some basic debugging
This commit is contained in:
parent
868305cc63
commit
e12618a688
|
|
@ -4,6 +4,7 @@ import {
|
|||
EffectTag,
|
||||
isFunctionFiber,
|
||||
isHostFiber,
|
||||
StateHook,
|
||||
type Child,
|
||||
type FiberNode,
|
||||
type FunctionFiber,
|
||||
|
|
@ -90,16 +91,44 @@ function createFiberFromElement(element: JSXElement): FiberNode {
|
|||
effectTag: EffectTag.NoEffect,
|
||||
alternate: 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) {
|
||||
wipFiber = fiber;
|
||||
hookIndex = 0;
|
||||
wipFiber.hooks = [];
|
||||
wipFiber.effectTag = EffectTag.NoEffect;
|
||||
const children = [fiber.type(fiber.pendingProps)];
|
||||
reconcileChildren(fiber, children);
|
||||
if (fiber.alternate && canBailout(fiber)) {
|
||||
fiber.pendingChildren = fiber.alternate.pendingChildren;
|
||||
} else {
|
||||
fiber.pendingChildren = [fiber.type(fiber.pendingProps)];
|
||||
}
|
||||
reconcileChildren(fiber, fiber.pendingChildren);
|
||||
}
|
||||
|
||||
function updateHostComponent(fiber: HostFiber) {
|
||||
|
|
@ -128,6 +157,26 @@ function pushEffect(fiber: FiberNode) {
|
|||
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(
|
||||
wipFiber: FiberNode | RootFiber,
|
||||
children: Child[] = [],
|
||||
|
|
@ -150,21 +199,9 @@ function reconcileChildren(
|
|||
|
||||
const isSameType = oldFiber && element && element.type === oldFiber.type;
|
||||
if (isSameType && oldFiber) {
|
||||
newFiber = {
|
||||
$$typeof: FiberNodeSymbol,
|
||||
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,
|
||||
};
|
||||
newFiber = createAlternate(oldFiber);
|
||||
newFiber.key = element.key ?? null;
|
||||
newFiber.pendingProps = element.props;
|
||||
pushEffect(newFiber);
|
||||
}
|
||||
|
||||
|
|
@ -183,6 +220,8 @@ function reconcileChildren(
|
|||
effectTag: EffectTag.Placement,
|
||||
alternate: null,
|
||||
nextEffect: null,
|
||||
actions: null,
|
||||
pendingChildren: [],
|
||||
};
|
||||
pushEffect(newFiber);
|
||||
}
|
||||
|
|
@ -394,6 +433,8 @@ export function createRootFiber(root: HTMLElement): RootFiber {
|
|||
isRoot: true,
|
||||
firstEffect: null,
|
||||
lastEffect: null,
|
||||
actions: null,
|
||||
pendingChildren: [],
|
||||
};
|
||||
const rootFiber: RootFiber = {
|
||||
$$typeof: FiberNodeSymbol,
|
||||
|
|
@ -412,6 +453,8 @@ export function createRootFiber(root: HTMLElement): RootFiber {
|
|||
isRoot: true,
|
||||
firstEffect: null,
|
||||
lastEffect: null,
|
||||
actions: null,
|
||||
pendingChildren: [],
|
||||
};
|
||||
alternate.alternate = rootFiber;
|
||||
for (const event of events) {
|
||||
|
|
@ -432,3 +475,20 @@ export function render(rootFiber: RootFiber, element: JSXElement) {
|
|||
};
|
||||
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";
|
||||
|
||||
let renderCount = 0;
|
||||
|
||||
const Child = () => {
|
||||
logFiber("Child");
|
||||
return <div>Child</div>;
|
||||
};
|
||||
|
||||
const App = () => {
|
||||
console.log("render");
|
||||
const items = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
||||
|
|
@ -15,6 +21,7 @@ const App = () => {
|
|||
}}
|
||||
>
|
||||
Hello world {String(++renderCount)}
|
||||
<Child />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -42,11 +42,17 @@ export const EffectHook = Symbol.for("cr.effect-hook");
|
|||
type Hook =
|
||||
| {
|
||||
type: typeof StateHook;
|
||||
value: any;
|
||||
}
|
||||
| {
|
||||
type: typeof EffectHook;
|
||||
};
|
||||
|
||||
type Action = {
|
||||
execute: (fiber: FiberNode) => void;
|
||||
nextAction: null | Action;
|
||||
};
|
||||
|
||||
export interface FiberNode {
|
||||
$$typeof: typeof FiberNodeSymbol;
|
||||
// Identity
|
||||
|
|
@ -63,12 +69,14 @@ export interface FiberNode {
|
|||
dom: Node | null;
|
||||
hooks: Hook[];
|
||||
pendingProps: any;
|
||||
pendingChildren: Child[];
|
||||
|
||||
effectTag: EffectTag;
|
||||
|
||||
// Used for double buffering
|
||||
alternate: FiberNode | null;
|
||||
nextEffect: FiberNode | null;
|
||||
actions: Action | null;
|
||||
}
|
||||
|
||||
export type FunctionFiber = FiberNode & {
|
||||
|
|
|
|||
Loading…
Reference in New Issue