Skip to content

Commit 6bb3fb5

Browse files
committed
feat: add fiber-based hook implementations
Add useState, useEffect, useRef, useMemo, useCallback, useReducer, and useContext hooks on the fiber architecture. Update context module to use fiber tree traversal for value lookup.
1 parent 0652684 commit 6bb3fb5

File tree

2 files changed

+858
-53
lines changed

2 files changed

+858
-53
lines changed

src/context/index.ts

Lines changed: 53 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -3,41 +3,17 @@
33
/* ***************** */
44

55
import { createElement } from "../core";
6-
import type {
7-
AnyMiniReactElement,
8-
FunctionalComponent,
9-
VDOMInstance,
10-
} from "../core/types";
6+
import type { AnyMiniReactElement, FunctionalComponent } from "../core/types";
7+
import { getCurrentlyRenderingFiber } from "../fiber/fiberHooks";
8+
import type { Fiber } from "../fiber/types";
119
import type { MiniReactContext } from "./types";
1210

13-
// Context system - Track context providers in the render tree
14-
const contextStack: Map<symbol, unknown>[] = [];
15-
16-
// Hook state management
17-
let currentRenderInstance: VDOMInstance | null = null;
18-
19-
/**
20-
* Sets the current render instance for context hooks
21-
* @param instance The current VDOM instance
22-
*/
23-
export function setContextRenderInstance(instance: VDOMInstance | null): void {
24-
currentRenderInstance = instance;
25-
}
26-
27-
/**
28-
* Pushes a context value onto the context stack
29-
* @param contextValues The context values to push
30-
*/
31-
export function pushContextValues(contextValues: Map<symbol, unknown>): void {
32-
contextStack.push(contextValues);
33-
}
34-
35-
/**
36-
* Pops a context value from the context stack
37-
*/
38-
export function popContextValues(): void {
39-
contextStack.pop();
40-
}
11+
// Map from Provider function to its context object
12+
// Used to identify Provider fibers when traversing the tree
13+
const providerToContext = new WeakMap<
14+
FunctionalComponent<{ value: unknown; children?: AnyMiniReactElement[] }>,
15+
MiniReactContext<unknown>
16+
>();
4117

4218
/**
4319
* createContext function - Creates a new context object with default value
@@ -61,14 +37,6 @@ export function createContext<T>(defaultValue: T): MiniReactContext<T> {
6137
// Update the context's current value to keep it in sync
6238
context._currentValue = value;
6339

64-
// Store context value in the current instance so reconciler can manage context stack
65-
if (currentRenderInstance) {
66-
if (!currentRenderInstance.contextValues) {
67-
currentRenderInstance.contextValues = new Map();
68-
}
69-
currentRenderInstance.contextValues.set(contextId, value);
70-
}
71-
7240
// Render children
7341
let result: AnyMiniReactElement | null = null;
7442
if (!children || children.length === 0) {
@@ -89,28 +57,60 @@ export function createContext<T>(defaultValue: T): MiniReactContext<T> {
8957
// Set the Provider function on the context object
9058
context.Provider = Provider;
9159

60+
// Register Provider function with its context for fiber traversal lookup
61+
providerToContext.set(
62+
Provider as FunctionalComponent<{
63+
value: unknown;
64+
children?: AnyMiniReactElement[];
65+
}>,
66+
context as MiniReactContext<unknown>,
67+
);
68+
9269
return context;
9370
}
9471

72+
/**
73+
* Finds the context value by traversing up the fiber tree.
74+
* Returns the value from the nearest Provider or the default value.
75+
*/
76+
function findContextValue<T>(fiber: Fiber, context: MiniReactContext<T>): T {
77+
let currentFiber: Fiber | null = fiber.return;
78+
79+
while (currentFiber !== null) {
80+
// Check if this fiber is a Provider for our context
81+
const fiberType = currentFiber.type;
82+
if (typeof fiberType === "function") {
83+
const providerContext = providerToContext.get(
84+
fiberType as FunctionalComponent<{
85+
value: unknown;
86+
children?: AnyMiniReactElement[];
87+
}>,
88+
);
89+
if (providerContext === (context as MiniReactContext<unknown>)) {
90+
// Found the Provider! Get the value from its props
91+
const props = currentFiber.memoizedProps ?? currentFiber.pendingProps;
92+
if (props && "value" in props) {
93+
return props["value"] as T;
94+
}
95+
}
96+
}
97+
currentFiber = currentFiber.return;
98+
}
99+
100+
// No Provider found, return default value
101+
return context._defaultValue;
102+
}
103+
95104
/**
96105
* useContext hook implementation
97106
* @param context The context object created by createContext
98107
* @returns The current context value
99108
*/
100109
export function useContext<T>(context: MiniReactContext<T>): T {
101-
if (!currentRenderInstance) {
110+
const currentFiber = getCurrentlyRenderingFiber();
111+
if (currentFiber === null) {
102112
throw new Error("useContext must be called inside a functional component");
103113
}
104114

105-
// Check the global context stack for active context values
106-
for (let i = contextStack.length - 1; i >= 0; i--) {
107-
const contextMap = contextStack[i];
108-
if (contextMap.has(context._contextId)) {
109-
const value = contextMap.get(context._contextId) as T;
110-
return value;
111-
}
112-
}
113-
114-
// Return default value if no provider found
115-
return context._defaultValue;
115+
return findContextValue(currentFiber, context);
116116
}

0 commit comments

Comments
 (0)