vaderjs 2.3.12 → 2.3.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.ts +108 -25
- package/package.json +1 -1
package/index.ts
CHANGED
|
@@ -287,11 +287,52 @@ function updateDom(dom: Node, prevProps: any, nextProps: any): void {
|
|
|
287
287
|
function commitRoot(): void {
|
|
288
288
|
deletions.forEach(commitWork);
|
|
289
289
|
commitWork(wipRoot.child);
|
|
290
|
+
|
|
291
|
+
// Run effects after DOM is committed
|
|
292
|
+
runEffects(wipRoot);
|
|
293
|
+
|
|
290
294
|
currentRoot = wipRoot;
|
|
291
295
|
wipRoot = null;
|
|
292
296
|
isRenderScheduled = false;
|
|
293
297
|
}
|
|
294
298
|
|
|
299
|
+
function runEffects(fiber: Fiber | null): void {
|
|
300
|
+
if (!fiber) return;
|
|
301
|
+
|
|
302
|
+
// Run effects for this fiber
|
|
303
|
+
if (fiber._pendingEffects) {
|
|
304
|
+
fiber._pendingEffects.forEach(({ callback, cleanup, hookIndex }) => {
|
|
305
|
+
// Run cleanup from previous effect
|
|
306
|
+
if (cleanup) {
|
|
307
|
+
try {
|
|
308
|
+
cleanup();
|
|
309
|
+
} catch (err) {
|
|
310
|
+
console.error('Error in effect cleanup:', err);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Run the new effect
|
|
315
|
+
try {
|
|
316
|
+
const newCleanup = callback();
|
|
317
|
+
|
|
318
|
+
// Store the cleanup function in the hook
|
|
319
|
+
if (fiber.hooks && fiber.hooks[hookIndex]) {
|
|
320
|
+
fiber.hooks[hookIndex]._cleanupFn = typeof newCleanup === 'function' ? newCleanup : undefined;
|
|
321
|
+
}
|
|
322
|
+
} catch (err) {
|
|
323
|
+
console.error('Error in effect:', err);
|
|
324
|
+
}
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
// Clear pending effects
|
|
328
|
+
fiber._pendingEffects = [];
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// Recursively run effects for children
|
|
332
|
+
runEffects(fiber.child);
|
|
333
|
+
runEffects(fiber.sibling);
|
|
334
|
+
}
|
|
335
|
+
|
|
295
336
|
/**
|
|
296
337
|
* Recursively commits a fiber and its children to the DOM.
|
|
297
338
|
* @param {Fiber} fiber - The fiber to commit.
|
|
@@ -468,9 +509,14 @@ function updateFunctionComponent(fiber: Fiber) {
|
|
|
468
509
|
fiber.hooks = [];
|
|
469
510
|
}
|
|
470
511
|
|
|
471
|
-
// Copy hooks from alternate
|
|
512
|
+
// Copy hooks from alternate but ensure they're fresh
|
|
472
513
|
if (fiber.alternate?.hooks) {
|
|
473
|
-
|
|
514
|
+
// Create new hooks array with same structure
|
|
515
|
+
fiber.hooks = fiber.alternate.hooks.map(altHook => {
|
|
516
|
+
// Create a shallow copy to avoid mutation issues
|
|
517
|
+
const newHook = { ...altHook };
|
|
518
|
+
return newHook;
|
|
519
|
+
});
|
|
474
520
|
}
|
|
475
521
|
|
|
476
522
|
// Call the component function
|
|
@@ -677,17 +723,16 @@ export function useStableRef<T>(initialValue: T | null = null): { current: T | n
|
|
|
677
723
|
* @param {T|(() => T)} initial - The initial state value or initializer function.
|
|
678
724
|
* @returns {[T, (action: T | ((prevState: T) => T)) => void]} A stateful value and a function to update it.
|
|
679
725
|
*/
|
|
680
|
-
|
|
681
726
|
|
|
682
|
-
|
|
683
|
-
// Add this to your useState hook to ensure re-renders
|
|
684
727
|
export function useState<T>(initial: T | (() => T)): [T, (action: T | ((prevState: T) => T)) => void] {
|
|
685
728
|
if (!wipFiber) {
|
|
686
729
|
throw new Error("Hooks can only be called inside a Vader.js function component.");
|
|
687
730
|
}
|
|
688
731
|
|
|
689
732
|
const currentHookIndex = hookIndex;
|
|
690
|
-
|
|
733
|
+
const currentFiber = wipFiber; // Capture current fiber
|
|
734
|
+
|
|
735
|
+
let hook = currentFiber.hooks[currentHookIndex];
|
|
691
736
|
|
|
692
737
|
if (!hook) {
|
|
693
738
|
hook = {
|
|
@@ -695,27 +740,66 @@ export function useState<T>(initial: T | (() => T)): [T, (action: T | ((prevStat
|
|
|
695
740
|
queue: [],
|
|
696
741
|
_needsUpdate: false
|
|
697
742
|
};
|
|
698
|
-
|
|
743
|
+
currentFiber.hooks[currentHookIndex] = hook;
|
|
699
744
|
}
|
|
700
745
|
|
|
746
|
+
// Create setState that captures current hook and fiber
|
|
701
747
|
const setState = (action: T | ((prevState: T) => T)) => {
|
|
702
|
-
//
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
if (!Object.is(hook.state, newState)) {
|
|
708
|
-
hook.state = newState;
|
|
748
|
+
// Use setTimeout to ensure we're outside the current render cycle
|
|
749
|
+
setTimeout(() => {
|
|
750
|
+
// Re-find the hook in the current fiber (in case it moved)
|
|
751
|
+
const fiber = currentRoot || wipRoot;
|
|
752
|
+
if (!fiber) return;
|
|
709
753
|
|
|
710
|
-
//
|
|
711
|
-
|
|
712
|
-
|
|
754
|
+
// Find the component fiber that owns this hook
|
|
755
|
+
let targetFiber = findFiberWithHook(fiber, currentFiber, currentHookIndex);
|
|
756
|
+
if (!targetFiber || !targetFiber.hooks) return;
|
|
757
|
+
|
|
758
|
+
const targetHook = targetFiber.hooks[currentHookIndex];
|
|
759
|
+
if (!targetHook) return;
|
|
760
|
+
|
|
761
|
+
// Calculate new state
|
|
762
|
+
const newState = typeof action === "function"
|
|
763
|
+
? (action as (prevState: T) => T)(targetHook.state)
|
|
764
|
+
: action;
|
|
765
|
+
|
|
766
|
+
if (!Object.is(targetHook.state, newState)) {
|
|
767
|
+
targetHook.state = newState;
|
|
768
|
+
targetHook._needsUpdate = true;
|
|
769
|
+
|
|
770
|
+
// Schedule a re-render
|
|
771
|
+
scheduleRender();
|
|
772
|
+
}
|
|
773
|
+
}, 0);
|
|
713
774
|
};
|
|
714
775
|
|
|
715
776
|
hookIndex++;
|
|
716
777
|
return [hook.state, setState];
|
|
717
778
|
}
|
|
718
779
|
|
|
780
|
+
// Helper to find the fiber containing a specific hook
|
|
781
|
+
function findFiberWithHook(root: Fiber, targetFiber: Fiber, hookIndex: number): Fiber | null {
|
|
782
|
+
// Simple BFS to find the fiber
|
|
783
|
+
let queue: Fiber[] = [root];
|
|
784
|
+
|
|
785
|
+
while (queue.length > 0) {
|
|
786
|
+
const fiber = queue.shift()!;
|
|
787
|
+
|
|
788
|
+
// Check if this is our target fiber
|
|
789
|
+
if (fiber === targetFiber ||
|
|
790
|
+
(fiber.type === targetFiber.type &&
|
|
791
|
+
fiber.key === targetFiber.key)) {
|
|
792
|
+
return fiber;
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
// Add children to queue
|
|
796
|
+
if (fiber.child) queue.push(fiber.child);
|
|
797
|
+
if (fiber.sibling) queue.push(fiber.sibling);
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
return null;
|
|
801
|
+
}
|
|
802
|
+
|
|
719
803
|
/**
|
|
720
804
|
* Schedules a re-render of the entire app
|
|
721
805
|
*/
|
|
@@ -756,15 +840,14 @@ export function useEffect(callback: Function, deps?: any[]): void {
|
|
|
756
840
|
deps.some((dep, i) => !Object.is(dep, hook.deps[i]));
|
|
757
841
|
|
|
758
842
|
if (hasChanged) {
|
|
759
|
-
|
|
760
|
-
hook._cleanupFn();
|
|
761
|
-
}
|
|
843
|
+
// Schedule effect to run after render
|
|
762
844
|
setTimeout(() => {
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
845
|
+
if (hook._cleanupFn) {
|
|
846
|
+
hook._cleanupFn();
|
|
847
|
+
}
|
|
848
|
+
const cleanup = callback();
|
|
849
|
+
if (typeof cleanup === 'function') {
|
|
850
|
+
hook._cleanupFn = cleanup;
|
|
768
851
|
}
|
|
769
852
|
}, 0);
|
|
770
853
|
}
|