Skip to content

Instantly share code, notes, and snippets.

@richnicholls404
Last active December 8, 2016 11:50
Show Gist options
  • Save richnicholls404/f078d95cab9095e5231e9cfaee761c8d to your computer and use it in GitHub Desktop.
Save richnicholls404/f078d95cab9095e5231e9cfaee761c8d to your computer and use it in GitHub Desktop.
Store a Meteor Collection in Redux
import { combineReducers, dispatch } from 'redux';
import * as '_' from 'lodash';
//globals: SubsManager
import { MyCollection } from './MyCollection';
// queue initial data load, otherwise you could be making 1000s of pointless immutable objects
const queuedState = {};
// watch changes to the collection. Save changes before ready to a queue, otherwise dispatch action on store
MyCollection.find().observeChanges({
// added events
added(id, fields) {
// add to queued state if collection is not ready yet
if (!SubsManager.ready()) {
if (queuedState[MyCollection.name] === undefined) {
queuedState[MyCollection.name] = {};
}
queuedState[MyCollection.name][id] = fields;
}
//else add to state
else {
dispatch({
type: 'ADD_DATA',
payload: {
id,
fields,
collectionName: MyCollection.name
}
});
}
},
// changed events
changed(id, fields) {
if (!SubsManager.ready()) { //unlikely? impossible?
queuedState[MyCollection.name][id] = fields;
}
else {
dispatch({
type: 'CHANGE_DATA',
payload: {
id,
fields,
collectionName: MyCollection.name
}
});
}
},
// removed events
removed(id) {
if (!SubsManager.ready()) { //unlikely? impossible?
delete queuedState[MyCollection.name][id];
}
else {
dispatch({
type: 'REMOVE_DATA',
payload: {
id,
collectionName: MyCollection.name
}
});
}
}
});
// wait for collection to be ready before adding queue
Tracker.autorun(() => {
if (SubsManager.ready()) {
dispatch({
type: 'PROCESS_QUEUED_DATA',
payload: {
queuedData: queuedData
}
});
}
});
// reducer
function dataStorageReducer(state = {}, action) {
switch (action.type) {
// add data - put it straight in
case ADD_DATA:
return _.defaultsDeep({}, {
[action.payload.collectionName]: {
[action.payload.id]: action.payload.fields
}
}, state);
// change data - you'll only get the updated fields, so merge with the data we already have
case CHANGE_DATA:
const oldData = _.getIn(state, [action.payload.collectionName, action.payload.id]);
const newData = _.defaults(fields, oldData);
return _.defaultsDeep({}, {
[action.payload.collectionName]: {
[action.payload.id]: newData
}
}, state);
// remove data - just get rid of it
case REMOVE_DATA:
return _.unset(
_.defaultsDeep({}, state), [action.payload.collectionName, action.payload.id]
);
// queued data - just put it in
case 'PROCESS_QUEUED_DATA':
return _.defaultsDeep({}, action.payload.queuedData);
default:
return state;
}
}
// register reducer
const todoApp = combineReducers({
dataStorageReducer
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment