-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(hydration): implement guard for store hydration management
- Loading branch information
1 parent
435dad3
commit 2f5342f
Showing
9 changed files
with
224 additions
and
102 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import type { ReactNode, FC } from "react"; | ||
|
||
import { useGeneratorStore, useHistoryStore, useStartupStore } from "@/stores"; | ||
|
||
/** | ||
* Props for the HydrationGuard component | ||
* @interface HydrationGuardProps | ||
* @property {ReactNode} children - Child components to render once stores are hydrated | ||
*/ | ||
interface HydrationGuardProps { | ||
children: ReactNode; | ||
} | ||
|
||
/** | ||
* HydrationGuard ensures that all required Zustand stores are hydrated before rendering children. | ||
* This prevents hydration mismatches and ensures consistent state management across the application. | ||
* | ||
* @component | ||
* @example | ||
* ```tsx | ||
* <HydrationGuard> | ||
* <App /> | ||
* </HydrationGuard> | ||
* ``` | ||
* | ||
* If any store is not yet hydrated, it returns null to prevent premature rendering. | ||
*/ | ||
export const HydrationGuard: FC<HydrationGuardProps> = ({ children }) => { | ||
const isGeneratorReady = useGeneratorStore((state) => state._hasHydrated); | ||
const isHistoryReady = useHistoryStore((state) => state._hasHydrated); | ||
const isStartupReady = useStartupStore((state) => state._hasHydrated); | ||
|
||
if (!isGeneratorReady || !isHistoryReady || !isStartupReady) { | ||
return null; | ||
} | ||
|
||
return <>{children}</>; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import type { HydrationState, WithHydration } from "./types"; | ||
|
||
/** | ||
* Service class for managing hydration state in Zustand stores | ||
* Provides utilities for handling store rehydration from persistent storage | ||
*/ | ||
export class HydrationService { | ||
/** | ||
* Returns the hydration configuration for persist middleware | ||
* Includes callback to mark store as hydrated after rehydration | ||
* | ||
* @template T - Type of the store state | ||
* @returns Configuration object with onRehydrateStorage callback | ||
* | ||
* @example | ||
* ```typescript | ||
* export const useStore = create<YourStoreType>()( | ||
* persist( | ||
* (set) => ({ | ||
* // Store state | ||
* }), | ||
* { | ||
* ...HydrationService.getHydrationConfig(), | ||
* storage: customStorage, | ||
* } | ||
* ) | ||
* ); | ||
* ``` | ||
*/ | ||
static getHydrationConfig<T>() { | ||
return { | ||
onRehydrateStorage: (state: WithHydration<T>) => { | ||
return () => state.setHasHydrated(true); | ||
}, | ||
}; | ||
} | ||
|
||
/** | ||
* Returns state object with hydration flag set to true | ||
* Used to mark store as hydrated | ||
* | ||
* @returns Hydration state object with _hasHydrated set to true | ||
* | ||
* @example | ||
* ```typescript | ||
* setHasHydrated: () => set(() => HydrationService.setStateAsHydrated()) | ||
* ``` | ||
*/ | ||
static setStateAsHydrated(): HydrationState { | ||
return { | ||
_hasHydrated: true, | ||
}; | ||
} | ||
|
||
/** | ||
* Returns initial hydration state | ||
* Used when initializing store | ||
* | ||
* @returns Initial hydration state with _hasHydrated set to false | ||
* | ||
* @example | ||
* ```typescript | ||
* export const useStore = create()((set) => ({ | ||
* ...HydrationService.getInitialState(), | ||
* // Other initial state | ||
* })); | ||
* ``` | ||
*/ | ||
static getInitialState(): HydrationState { | ||
return { | ||
_hasHydrated: false, | ||
}; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.