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.
Files changed (2) hide show
  1. package/index.ts +108 -25
  2. 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 if it exists
512
+ // Copy hooks from alternate but ensure they're fresh
472
513
  if (fiber.alternate?.hooks) {
473
- fiber.hooks = fiber.alternate.hooks.map(hook => ({ ...hook }));
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
- let hook = wipFiber.hooks[currentHookIndex];
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
- wipFiber.hooks[currentHookIndex] = hook;
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
- // Calculate new state
703
- const newState = typeof action === "function"
704
- ? (action as (prevState: T) => T)(hook.state)
705
- : action;
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
- // Schedule a re-render starting from the component's fiber
711
- scheduleRender();
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
- if (hook._cleanupFn) {
760
- hook._cleanupFn();
761
- }
843
+ // Schedule effect to run after render
762
844
  setTimeout(() => {
763
- const newCleanup = callback();
764
- if (typeof newCleanup === 'function') {
765
- hook._cleanupFn = newCleanup;
766
- } else {
767
- hook._cleanupFn = undefined;
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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vaderjs",
3
- "version": "2.3.12",
3
+ "version": "2.3.13",
4
4
  "description": "A simple and powerful JavaScript library for building modern web applications.",
5
5
  "bin": {
6
6
  "vaderjs": "./main.js"