Last active
July 22, 2017 13:50
-
-
Save typoerr/fe80de3f64c6bf32f40fdddc4ab0c8f3 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
| /* | |
| - storeとつながる | |
| - selectorをstreamで書ける | |
| */ | |
| import { h, Component, ComponentConstructor, FunctionalComponent } from 'preact'; | |
| import { Stream, Subscription, from, mergeArray } from 'most'; | |
| import { async } from 'most-subject'; | |
| import { Store } from 'redux'; | |
| import { noop } from '@utils'; | |
| const assign = (o1: any, o2: any) => Object.assign({}, o1, o2); | |
| export type AnyComponent<P> = ComponentConstructor<P, any> | FunctionalComponent<P>; | |
| export interface RequireCtx<S = any> { | |
| store: Store<S>; | |
| } | |
| export interface InitSelector<CP, S, OP = {}, C= {}> { | |
| (state: S, initialProps: OP, context: C): CP; | |
| } | |
| export interface Selector<CP, S, OP = {}, C = {}> { | |
| (state$: Stream<S>, initialProps: OP, context: C): Stream<Partial<CP>>; | |
| } | |
| export function connect<CP, S, OP>(init: InitSelector<CP, S, OP>, ...selector: Selector<CP, S, OP>[]) { | |
| return (component: AnyComponent<CP>): ComponentConstructor<OP, any> => { | |
| return class WrapperComponent extends Component<OP, any> { | |
| static displayName = `Connect(${component.name})`; | |
| context: RequireCtx<S>; | |
| nextProps = {}; | |
| protected store = this.context.store; | |
| protected state$ = from<S>(this.context.store as any).multicast(); | |
| protected in$ = async<S>(); | |
| protected subscriptions: Subscription<any>[] = []; | |
| constructor(props: any, context: any) { | |
| super(props, context); | |
| const state = this.store.getState(); | |
| this.nextProps = init(state, props, context); | |
| const sub = this.state$.subscribe({ | |
| next: (s) => this.in$.next(s), | |
| error: (e) => { throw e; }, | |
| complete: noop | |
| }); | |
| this.subscriptions.push(sub); | |
| } | |
| componentWillMount() { | |
| const next = () => this.forceUpdate(); | |
| const error = (err: Error) => { throw err; }; | |
| const subscriber = { next, error, complete: noop }; | |
| const arr$ = selector.map(s => s(this.in$, this.props, this.context)); | |
| const selectors$ = mergeArray(arr$); | |
| const sub = selectors$ | |
| .scan(assign, this.nextProps) | |
| .tap(x => this.nextProps = x) | |
| .debounce(0) // 連続した同期的なstreamによるviewの更新を間引く | |
| .subscribe(subscriber); | |
| this.subscriptions.push(sub); | |
| } | |
| componentWillUnMount() { | |
| this.subscriptions.forEach(sub => sub.unsubscribe()); | |
| } | |
| render(props: any) { | |
| return h(component, { ...props, ...this.nextProps }); | |
| } | |
| }; | |
| }; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment