import React, { createContext } from 'react' import { Component, ReactNode, Context, ComponentType } from 'react' import equal from 'fast-deep-equal' export interface ProviderProps { initial?: T } export type PrevState = (prevState: T) => T export type GetFn = (state: T) => ReactNode export type Dispatch = T | PrevState export interface State { context: Context set: (param: Dispatch) => void Provider: ComponentType> } export function create(initial: T): State { const ctx = createContext(initial) const listeners = new Set() const dispatch = (fn: Dispatch) => { listeners.forEach((listener: any) => listener(fn)) } return { context: ctx, set: fn => dispatch(fn), Provider: class Provider extends Component, T> { public static displayName = 'DoczStateProvider' public static getDerivedStateFromProps(props: any, state: any): any { if (!equal(props.initial, state)) return props.initial return null } public state = this.props.initial || initial || ({} as T) public componentDidMount(): void { listeners.add((fn: Dispatch) => this.setState(fn)) } public componentWillUnmount(): void { listeners.clear() } public render(): ReactNode { return ( {this.props.children} ) } }, } }