33/* ***************** */
44
55import { 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" ;
119import 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 */
100109export 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