Skip to content

Instantly share code, notes, and snippets.

@nmn
Created April 7, 2015 10:40
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nmn/97440d0cdf08f6b5a2d2 to your computer and use it in GitHub Desktop.
Save nmn/97440d0cdf08f6b5a2d2 to your computer and use it in GitHub Desktop.
Observe API with JS-CSP Mults
import React, { Component } from 'react'
import {operations, chan, go, take, CLOSED} from 'js-csp'
const {mult} = operations
export default function polyfillObserve(ComposedComponent, observe) {
observe = observe || ComposedComponent.observe
if(!observe){
return ComposedComponent
}
const Enhancer = class extends Component {
constructor(props, context) {
super(props, context)
this.channels = {}
this.mults = {}
this.state = { data: {} }
this.resubscribe(props, context)
}
componentWillReceiveProps(props, context) {
this.resubscribe(props, context)
}
componentWillUnmount() {
this.unsubscribe()
}
setUpSubscription(key, ch){
const that = this
go(function*(){
while(true){
let value = yield take(ch)
if(value === CLOSED){
return
}
that.setState({[key]: value})
}
})
}
resubscribe(props, context) {
const newMults = observe(props, context)
const commonChannels = Object.keys(newMults).filter(key => !!this.channels[key])
const addedChannels = Object.keys(newMults).filter(key => !this.channels[key])
const removedChannels = Object.keys(this.channels).filter(key => !newMults[key])
commonChannels.forEach(key => {
if(newMults[key] !== this.mults[key]){
mult.tap(newMults[key], this.channels[key])
mult.untap(this.mults[key], this.channels[key])
}
})
addedChannels.forEach(key => {
this.channels[key] = chan()
mult.tap(newMults[key], this.channels[key])
this.setUpSubscription(key, this.channels[key])
})
removedChannels.forEach(key => {
mult.untap(this.mults[key], this.channels[key])
this.channels[key].close()
delete this.channels[key]
})
this.mults = newMults
}
unsubscribe() {
Object.keys(this.channels).forEach(key => {
mult.untap(this.mults[key], this.channels[key])
this.channels[key].close()
})
this.channels = {}
this.mults = {}
}
render() {
return <ComposedComponent {...this.props} data={this.state.data} />
}
}
Enhancer.propTypes = ComposedComponent.propTypes
Enhancer.contextTypes = ComposedComponent.contextTypes
return Enhancer
}
@nmn
Copy link
Author

nmn commented Apr 7, 2015

This is a possible way to implement the Observe API but based on JS-CSP Mults instead of Observables. Some minor benefits can be achieved by using a basic diffing strategy as well.

Usage:

// can't put this on component but this is good enough for playing
function observe(props, context) {
  return {
    yourStuff: getMult(stores[props.name])
  };
}

class YourComponent extends Component {
  render() {
    // Note: this.props.data, not this.data
    return <div>{this.props.data.yourStuff}</div>;
  }
}

export default polyfillObserve(YourComponent, observe);

OR

class YourComponent extends Component {
  render() {
    // Note: this.props.data, not this.data
    return <div>{this.props.data.yourStuff}</div>;
  }
}

YourComponent.observe: function(props, context) {
  return {
    yourStuff: getMult(stores[props.name])
  };
}

export default polyfillObserve(YourComponent, observe);

Assuming that getMult returns a mult created from a JS-CSP channel.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment