Last active
July 12, 2017 02:10
-
-
Save typoerr/d860c3f899440cb9a4558b00e680f6d5 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { h, Component, ComponentConstructor, FunctionalComponent } from 'preact'; | |
| import { Stream, mergeArray, Subscription } from 'most'; | |
| type AnyComponent<P> = ComponentConstructor<P, any> | FunctionalComponent<P>; | |
| export interface Action<T = any, K extends keyof T= any> { | |
| type: K; | |
| payload: T[K]; | |
| } | |
| export type Action$<A extends Action = any> = Stream<A>; | |
| export interface MergedCtx<P, S> { | |
| self: Component<P, S>; | |
| } | |
| export interface Epic<P, S, C, K extends keyof S> { | |
| (this: Component<P, S>, action$: Action$, ctx: C): Stream<Pick<S, K>>; | |
| } | |
| export interface Options<P, S> { | |
| updater?: (this: Component<P, S>, nextState: S) => void; | |
| } | |
| export const CONTEXT_KEY = 'STATEFUL_COMPONENT_CONTEXT'; | |
| export default function create<P= {}, S = {}>(state: S, options: Options<P, S> = {}) { | |
| return function applyEpics<K extends keyof S, C extends MergedCtx<P, S>>(...epics: Epic<P, S, C, K>[]) { | |
| return function applyComponent(component: AnyComponent<P & S>) { | |
| let subscription: Subscription<any>; | |
| return class WrappedComponent extends Component<P, S> { | |
| static displayName = `Stateful(${component.name})`; | |
| readonly state = state; | |
| protected update = options.updater ? options.updater.bind(this) : this.setState; | |
| constructor(props: any, context: any) { | |
| super(props, context); | |
| const { actionIn$, ...extra } = context[CONTEXT_KEY]; | |
| const ctx = Object.assign({}, extra, { self: this }); | |
| const epics$ = mergeArray(epics.map(ep => ep.call(this, actionIn$, ctx))); | |
| subscription = epics$.subscribe({ | |
| next: (x) => this.update(x), | |
| error: (e) => { throw e; }, | |
| complete: () => subscription && subscription.unsubscribe() | |
| }); | |
| } | |
| componentWillUnMount() { | |
| subscription && subscription.unsubscribe(); | |
| } | |
| render() { | |
| return h(component, { ...this.state as any, ...this.props as any }); | |
| } | |
| }; | |
| }; | |
| }; | |
| } |
Author
typoerr
commented
Jul 11, 2017
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment