sprinklers3/client/state/reactContext.tsx

52 lines
1.7 KiB
TypeScript
Raw Normal View History

2018-06-25 17:37:36 -06:00
import * as React from "react";
2018-08-07 21:21:26 +03:00
import { AppState } from "@client/state";
2018-06-25 17:37:36 -06:00
const StateContext = React.createContext<AppState | null>(null);
2018-06-25 17:37:36 -06:00
export interface ProvideStateProps {
state: AppState;
2018-06-25 17:37:36 -06:00
children: React.ReactNode;
}
export function ProvideState({ state, children }: ProvideStateProps) {
2018-06-25 17:37:36 -06:00
return (
<StateContext.Provider value={state}>
{children}
</StateContext.Provider>
);
}
export interface ConsumeStateProps {
children: (state: AppState) => React.ReactNode;
2018-06-25 17:37:36 -06:00
}
export function ConsumeState({ children }: ConsumeStateProps) {
const consumeState = (state: AppState | null) => {
2018-06-25 17:37:36 -06:00
if (state == null) {
throw new Error("Component with ConsumeState must be mounted inside ProvideState");
}
return children(state);
};
return <StateContext.Consumer>{consumeState}</StateContext.Consumer>;
}
type Diff<T extends string | number | symbol, U extends string | number | symbol> =
({[P in T]: P } & {[P in U]: never } & { [x: string]: never })[T];
type Omit<T, K extends keyof T> = {[P in Diff<keyof T, K>]: T[P]};
export function injectState<P extends { appState: AppState }>(Component: React.ComponentType<P>):
React.ComponentClass<Omit<P, "appState">> {
return class extends React.Component<Omit<P, "appState">> {
2018-06-25 17:37:36 -06:00
render() {
const consumeState = (state: AppState | null) => {
2018-06-25 17:37:36 -06:00
if (state == null) {
throw new Error("Component with injectState must be mounted inside ProvideState");
}
return <Component {...this.props} appState={state}/>;
2018-06-25 17:37:36 -06:00
};
return <StateContext.Consumer>{consumeState}</StateContext.Consumer>;
}
};
}