Skip to content

Instantly share code, notes, and snippets.

@abhiaiyer91
Created March 20, 2016 17:47
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 abhiaiyer91/fb558dde972db140bccb to your computer and use it in GitHub Desktop.
Save abhiaiyer91/fb558dde972db140bccb to your computer and use it in GitHub Desktop.
Workpop State Container using TrackerReact
function composeStateContainer(subscriptions, reactiveFn) {
return function wrappedComposeContainer(WrappedComponent) {
class ComposedContainer extends React.Component {
constructor() {
super();
this.state = {};
this._subscriptionHandles = {};
// This dependency is used to identify state transitions in
// _subscriptionHandles which could cause the result of
// Basically this is triggered whenever a new subscription
// handle is added or when a subscription handle
// is removed and they are not ready.
this._allSubsReadyDep = new Tracker.Dependency();
this._allSubsReady = false;
this.subHandle = {};
this.subscriptionImplementation = this.subscriptionImplementation.bind(this);
this.subscribe = this.subscribe.bind(this);
this.subscriptionsReady = this.subscriptionsReady.bind(this);
this.reactiveState = this.reactiveState.bind(this);
}
componentWillMount() {
subscriptions(this.subscribe);
}
componentWillUnmount() {
this.subHandle.stop();
}
subscriptionsReady() {
this._allSubsReadyDep.depend();
this._allSubsReady = _.all(this._subscriptionHandles, function (handle) {
return handle.ready();
});
return this._allSubsReady;
}
subscribe(/* arguments */) {
let subHandle;
const subHandles = this._subscriptionHandles;
const args = _.toArray(arguments);
let options = {};
if (_.size(args)) {
const lastParam = _.last(args);
// Match pattern to check if the last arg is an options argument
const lastParamOptionsPattern = {
onReady: Match.Optional(Function),
onStop: Match.Optional(Function),
connection: Match.Optional(Match.Any)
};
if (_.isFunction(lastParam)) {
options.onReady = args.pop();
} else if (lastParam && !_.isEmpty(lastParam) && Match.test(lastParam, lastParamOptionsPattern)) {
options = args.pop();
}
options.onStop = () => {
// When the subscription is stopped, remove it from the set of tracked
// subscriptions to avoid this list growing without bound
delete subHandles[subHandle.subscriptionId];
// Removing a subscription can only change the result of subscriptionsReady
// if we are not ready (that subscription could be the one blocking us being
// ready).
if (!this._allSubsReady) {
this._allSubsReadyDep.changed();
}
};
}
const connection = options.connection;
const callbacks = _.pick(options, ["onReady", "onError", "onStop"]);
// The callbacks are passed as the last item in the arguments array passed to subscribe
args.push(callbacks);
// subscribe takes the connection as one of the options in the last argument
subHandle = this.subscriptionImplementation(args, {
connection
});
if (!_.has(subHandles, subHandle.subscriptionId)) {
subHandles[subHandle.subscriptionId] = subHandle;
// Adding a new subscription will always cause us to transition from ready
// to not ready, but if we are already not ready then this can't make us
// ready.
if (this._allSubsReady) {
this._allSubsReadyDep.changed();
}
}
return subHandle;
}
reactiveState() {
return reactiveFn() || {};
}
subscriptionImplementation(args, options) {
const optionsObj = options || {};
if (optionsObj.connection) {
this.subHandle = optionsObj.connection.subscribe.apply(optionsObj.connection, args);
} else {
this.subHandle = Meteor.subscribe.apply(Meteor, args);
}
return this.subHandle;
}
render() {
const propsToComp = Object.assign({}, this.props, this.reactiveState());
if (this.subscriptionsReady()) {
return (
<div>
<WrappedComponent {...propsToComp} />
</div>
);
}
return (
<div>
{this.props.loading || "Loading..."}
</div>
);
}
}
// TODO: add this to the composition not as a mixin
reactMixin(ComposedContainer.prototype, TrackerReact);
return ComposedContainer;
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment