Skip to content

Provider (React Context)

The Provider pattern uses React Context to inject shared state into the component tree. A high-level component provides a value; descendant components access it via a hook — no prop drilling.

Combined with a generic factory, each application can type its own context.

graph TD
    Provider["XxxProvider\n(context value)"] --> Hook["useXxx()\n(typed access)"]
    Hook --> ComponentA["Component A"]
    Hook --> ComponentB["Component B"]
    Hook --> ComponentC["Component C"]

Every @granit/react-* package follows this pattern:

ProviderHookPackage
WorkflowProvideruseWorkflowConfig()@granit/react-workflow
TimelineProvideruseTimelineConfig()@granit/react-timeline
NotificationProvideruseNotificationContext()@granit/react-notifications
QueryProvideruseQueryConfig()@granit/react-querying
SettingsProvideruseSettingsConfig()@granit/react-settings
TemplatingProvideruseTemplatingConfig()@granit/templating
ExportProvider / ImportProvidercontext hooks@granit/react-data-exchange
ErrorContextProvideruseErrorContext()@granit/react-error-boundary
CookieConsentProvideruseCookieConsent()@granit/react-cookies
TracingProvideruseTracer()@granit/react-tracing
// createAuthContext<T>() creates both the context and the hook
export const { AuthContext, useAuth } = createAuthContext<AuthContextType>();

Each application defines its own AuthContextType extending BaseAuthContextType.

React applications need to share configuration (API client, base path) and state (connection status, current user) across deeply nested components. Context avoids prop drilling while keeping the dependency explicit — the hook throws if called outside its Provider.

// 1. Define typed context
interface AuthContextType extends BaseAuthContextType {
register: () => void;
}
export const { AuthContext, useAuth } = createAuthContext<AuthContextType>();
// 2. Provide value at the top of the tree
function AuthProvider({ children }: { children: React.ReactNode }) {
const value: AuthContextType = { /* ... */ };
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
}
// 3. Consume anywhere below
function NavBar() {
const { user, logout } = useAuth();
return <button onClick={logout}>{user?.name}</button>;
}
// 4. Mock for testing / Storybook
import { createMockProvider } from '@granit/react-authentication';
const MockAuth = createMockProvider(AuthContext, {
keycloak: null, authenticated: true, loading: false,
user: { sub: '1', name: 'Test' },
login: () => {}, logout: () => {}, register: () => {},
});