UNPKG

nesquirk

Version:

Ties Nes + minimongo together for gloryful reactive apps.

105 lines (81 loc) 2.52 kB
import React, { Component } from 'react' import PropTypes from 'prop-types' const noData = () => ({}) export default function createContainer (getData, opts, Comp) { if (!Comp) { Comp = opts opts = {} } opts = opts || {} getData = getData || noData const clientKey = opts.clientKey || 'client' class Container extends Component { static contextTypes = { [clientKey]: PropTypes.object.isRequired } state = { data: {} } componentWillMount () { this.subscribe(this.props, this.context) } componentWillReceiveProps (nextProps, nextContext) { this.resubscribe(nextProps, nextContext) } componentWillUnmount () { this.unsubscribe() } subscribe (props, context) { const client = opts.client || context[clientKey] const subs = [] const ctx = { subscribe () { const sub = client.subscribe.apply(client, arguments) subs.push(sub) return sub } } const data = getData.call(ctx, props) // Listen for changes for the collections that belongs to these subs this.getCollections(subs).forEach((c) => { c.on('change', this.onCollectionChange) }) subs.forEach((s) => s.on('ready', this.onSubscriptionReady)) this._subs = subs this.setState({ data }) } resubscribe (props, context) { const prevSubs = this._subs this.getCollections(prevSubs).forEach((c) => { c.removeListener('change', this.onCollectionChange) }) this.subscribe(props, context) prevSubs.forEach((s) => { s.removeListener('ready', this.onSubscriptionReady) s.stop() }) } unsubscribe () { const subs = this._subs this.getCollections(subs).forEach((c) => { c.removeListener('change', this.onCollectionChange) }) this._subs = [] subs.forEach((s) => { s.removeListener('ready', this.onSubscriptionReady) s.stop() }) } getCollections (subs) { return subs.reduce((collections, s) => { if (collections.includes(s.collection)) return collections return collections.concat(s.collection) }, []) } onSubscriptionReady = () => this.resubscribe(this.props, this.context) onCollectionChange = () => this.resubscribe(this.props, this.context) render () { const { props } = this return <Comp {...props} {...this.state.data} /> } } return Container }