import * as React from 'react'; import { Context, ReactNode } from 'react'; export type ServiceContainerContextValue = { serviceContainer: T; } | null; export const ServiceContainerContext: Context> = React.createContext>( null); export interface ServiceContainerProviderProps { children: ReactNode; factory: Promise; } export interface ServiceContainerProviderState { serviceContainer?: T; error: string | null; } /** * This ServiceContainerProvider can be nested with each other, passes to level container to all children. */ export class ServiceContainerProvider extends React.PureComponent, ServiceContainerProviderState> { public state: ServiceContainerProviderState = { error: null, }; public render(): React.ReactNode { const { children } = this.props; const { serviceContainer, error } = this.state; if (error) { throw error; } if (serviceContainer) { return ( {children}); } return ( {this.handleConsumeCallback} ); } private handleConsumeCallback = (value: ServiceContainerContextValue): ReactNode => { const { children, factory } = this.props; if (value && value.serviceContainer) { // We are a nested provider, so we can just return directly and let the parent provider handle the rest. return children; } factory .then((serviceContainer) => { this.setState({ serviceContainer }); }) .catch((error) => { this.setState({ error, }); }); return null; }; }