发现现在合用RxJS和React变得简单多了,论坛里也有其他用RxJS和React的同学吧,想抛砖引玉讨论下思路。
用了mapped types, 所以需要2.1以后的版本
import * as React from 'react'
import {Observable, Subject} from 'rxjs'
import {ISubscription} from 'rxjs/Subscription'
export abstract class ViewComponent<Props, State, Interactions> extends React.Component<Props, State> {
protected abstract readonly interactionFilters: InteractionFilters<Interactions> // 单个事件的过滤,例如debounce
protected abstract viewLogic(): ISubscription[]
private _interactionSubjects: Subjects<Interactions>
protected report: EventHandlers<Interactions>
protected interactions: Observables<Interactions>
constructor(props: Props) {
super(props)
this.setState = this.setState.bind(this) // 无关
}
componentWillMount(): void {
this._interactionSubjects = createSubjects<Interactions>(this.interactionFilters)
this.report = generateHandlers<Interactions>(this._interactionSubjects)
this.interactions = filterInteractions<Interactions>(this._interactionSubjects, this.interactionFilters)
this._jobs = this.viewLogic()
}
componentWillUnmount() {
this._jobs.forEach(job => job.unsubscribe())
}
private _jobs: ISubscription[]
}
type EventHandlers<Interactions> = {[Name in keyof Interactions]: (event: Interactions[Name])=> void}
type Subjects<Interactions> = {[Key in keyof Interactions]: Subject<Interactions[Key]>}
type Observables<Interactions> = {[Name in keyof Interactions]: Observable<Interactions[Name]>}
export type InteractionFilters<Interactions> = {
[Key in keyof Interactions]: (input: Observable<Interactions[Key]>)=> Observable<Interactions[Key]>
}
export let KeepOrigin = <T>(input: Observable<T>): Observable<T> => input
let createSubjects = <Interactions>(shape: {[Key in keyof Interactions]: any}): Subjects<Interactions> => {
let result: Subjects<Interactions> = {} as any
Object.keys(shape).forEach((key: keyof Interactions) => result[key] = new Subject<Interactions[typeof key]>())
return result
}
let generateHandlers = <Interactions>(subjects: Subjects<Interactions>): EventHandlers<Interactions> => {
let result: EventHandlers<Interactions> = {} as any
Object.keys(subjects).forEach((key: keyof Interactions) =>
result[key] = (event: Interactions[typeof key]) => subjects[key].next(event))
return result
}
let filterInteractions = <Interactions>(subjects: Subjects<Interactions>,
filters: InteractionFilters<Interactions>): Observables<Interactions> => {
let result: Observables<Interactions> = {} as any
Object.keys(subjects).forEach((key: keyof Interactions) => result[key] = filters[key](subjects[key]))
return result
}
用法:
class Example extends ViewComponent<Props, State, Interactions> {
interactionFilters: InteractionFilters<Interactions> = {
clicked: KeepOrigin
}
protected viewLogic(): ISubscription[] {
let {interactions} = this
return [interactions.clicked.subscribe(event=> console.log(event))]
}
render(){
let {report} = this
return <div onClick={report.clicked}>
</div>
}
}
type Interactions = {clicked: any}
type Props = {}
type State = {}
好处是把回调转成Observable的同时,可以获得IDE的正确代码提示和对事件的类型检查
this.interactions
里面是根据Interactions和InteractionFilters自动生成的很多Observable,这里是{clicked: Observable<any>}
之前看到Cyclejs的方案感觉也可以用在React上,也看到过友人的方案,各位是怎么连接RxJS和React的呢?