Skip to main content

Hydrator

The Hydrator component in Igris is a wrapper component that manages the hydration process for persisted stores and states. It provides a declarative way to handle hydration with loading states and ensures your application only renders after data is properly hydrated.

Basic Usage​

Using with Stores Directly​

import { Hydrator } from "igris/persistence";

function App() {
return (
<Hydrator stores={[usePersistedStore, usePersistedState]}>
<Main />
</Hydrator>
);
}

Using with Pre-configured Hydrator​

import { Hydrator, setupHydrator } from "igris/persistence";

const hydrator = setupHydrator([usePersistedStore, usePersistedState], {
storage: sessionStorage
});

function App() {
return (
<Hydrator handler={hydrator}>
<Main />
</Hydrator>
);
}

API Reference​

Hydrator Props​

The Hydrator component accepts two different prop configurations:

Configuration with Stores​

interface HydratorStoresConfig {
stores: (StateHook<AnyType> | StoreHook<AnyType, AnyType>)[];
config?: {
storage?: StorageProvider;
};
loadingComponent?: React.ReactNode | React.ReactNode[];
children: React.ReactNode | React.ReactNode[];
}

Configuration with Handler​

interface HydratorHandlerConfig {
handler: () => void | Promise<void>;
loadingComponent?: React.ReactNode | React.ReactNode[];
children: React.ReactNode | React.ReactNode[];
}

Advanced Usage​

Custom Loading Component​

function App() {
return (
<Hydrator
stores={[usePersistedStore, usePersistedState]}
loadingComponent={<CustomLoadingSpinner />}
>
<Main />
</Hydrator>
);
}

With Custom Storage​

function App() {
return (
<Hydrator
stores={[usePersistedStore, usePersistedState]}
config={{
storage: sessionStorage
}}
>
<Main />
</Hydrator>
);
}

With Pre-configured Handler and Loading State​

const hydrator = setupHydrator([usePersistedStore, usePersistedState]);

function App() {
return (
<Hydrator
handler={hydrator}
loadingComponent={
<div className="loading-state">
<Spinner />
<p>Loading application state...</p>
</div>
}
>
<Main />
</Hydrator>
);
}

TypeScript Interface​

export type HydratorOption =
| {
handler: () => void | Promise<void>;
stores?: never;
config?: never;
loadingComponent?: React.ReactNode | React.ReactNode[];
}
| {
handler?: never;
stores: (StateHook<AnyType> | StoreHook<AnyType, AnyType>)[];
config?: Partial<{
storage: StorageProvider;
}>;
loadingComponent?: React.ReactNode | React.ReactNode[];
};

export type HydratorProps = HydratorOption & {
children: React.ReactNode | React.ReactNode[];
};

Important Notes​

  1. The Hydrator component must be used at the root level of your application, above any components that use persisted stores or states.

  2. You must use either the stores prop or the handler prop, but not both:

    • Use stores for direct configuration
    • Use handler when you have a pre-configured hydrator from setupHydrator
  3. The loadingComponent prop is optional:

    • If not provided, nothing will be rendered during hydration
    • Can be any valid React node or array of nodes
  4. The component automatically manages the hydration lifecycle:

    • Initiates hydration on mount
    • Renders loading component during hydration
    • Renders children only after successful hydration

Example with Multiple Configuration Options​

import { Hydrator, setupHydrator } from "igris/persistence";
import { usePersistedStore, usePersistedState } from "./stores";

// Option 1: Direct configuration
function App1() {
return (
<Hydrator
stores={[usePersistedStore, usePersistedState]}
config={{ storage: sessionStorage }}
loadingComponent={<LoadingScreen />}
>
<Main />
</Hydrator>
);
}

// Option 2: Pre-configured handler
const hydrator = setupHydrator([usePersistedStore, usePersistedState], {
storage: sessionStorage
});

function App2() {
return (
<Hydrator
handler={hydrator}
loadingComponent={<LoadingScreen />}
>
<Main />
</Hydrator>
);
}