I was wondering if I could get some assitance in integrating redux with meteorjs.
Meteor's data management layer is in the form of:
Component subscribes to a Meteor publication via Meteor.subscribe('example')
This subscription dumbs data into Minimongo. A client side implementation of Mongodb.
The data is available under either isomorphic collections where Examples.findOne queries from the Examples collection in minimongo when in the client and mongodb on the server.
The cool thing about having this client side db is views become bound by a reactive library called Tracker. Tracker sets up dependencies for these client side methods and will update views reactively if the result of find/findOne change.
This is now where I get confused...since Redux is all about a single state atom, looking at a birds eye view of Meteor, a client side DB is already a single state atom containing any number of mini collections.
This poses a problem in 3 ways.
reducers aren't really doing any form of reduction.Tracker library will notify components of their state change automatically.Thus breaking the principles of redux entirely!!
Does anyone have an idea of how I can come to a solution that isnt breaking these principles? I don't want to be in a place where i'm neither redux nor meteor in order to integrate both.
Ideally, we need to be able to mutate client collections / server via side effects. Is a dispatch () => action creator the best way to do this? In that case, should my state return what the state of the client colllection is?
What about achieving this a different way, by approaching a client side db as temporal data? Storing the state in arrays on the document? This still breaks purity!
Im kinda lost! Any help would be appreciated! I was originally building a flux implementation for Meteor when a friend said that I was doing "Redux, but state mutations, so not really Redux"
Hey,
It's good timing. Actually, I am working on something this. I think we need to do it in the redux way. Reducers should be pure.
Action creators is a best places to put all the data stuff. We may need to create some binding to do subscriptions on the component. I'll work on sample today and let's discuss.
Hope redux community can help to fine tune it :)
Hi,
I've been working on this too, using @jedwards1211's project for now.
I'm going to reorganize the code as advised in @fzaninotto's article and to refactor it using meteor 1.3 ASAP. And I'm still looking for a way to have i18n working nicely with everything.
I'd love some feedback on the middlewares for Meteor integration. The project is here. So far, the react part is not tested but it will be soon too.
@djhi On the lines of what I was thinking!
Ideally in overview to any redux specific people reading this:
Initial State is just placeholder data as we know when we subscribe we'll be working with the right state.
Initial state can be hydrated with an action when the subscription is ready.
Action Creators will dispatch async actions to handle Meteor.calls.
If error, we'll dispatch error actions to revert state.
Data from subscriptions can be sent with the payload.
Business logic -> action creators
Essentially the dispatch()=> pattern is key for us Meteor folk.
@arunoda is this a good summary of what we discussed ?
@gaearon any validation to this?
@abhiaiyer91 @djhi @arunoda Are you guys aware of Mobservable https://mweststrate.github.io/mobservable/index.html much simpler solution for state management
Here is a talk from the creator of Mobservable https://www.youtube.com/watch?v=FEwLwiizlk0
@abhiaiyer91 yes.
@ansarizafar Actually, this is not new to us. We call it Tracker in Meteor :)
@ansarizafar To be specific, Mobservable is great and that's available(something similar) with Meteor from very early days. But the problem is, with this it's pretty hard to manage the predictable state.
State could be change in many places and it's hard to debug and manage it in the long run.
To keep actions simple and reducers pure, it would seem to me that the state storage would provided by the store or middleware?
I think "store enhancer" is the term for the concept I'm describing?
Hahah close! But we don't need it really!
Using connect we can make sure our components are synced with our redux stores. Thus for the client state of truth we can handle things the redux way.
When we want to alter state, thanks to Meteor, our action creators side effects will bring the balance we need. By sending data along with the payload from a store dispatch, we have the data we want t alter. We can do our business logic, return a new state, dispatch another action for the side effect. Our minimongo collections will update from this state change, and we can bind another action to componentWillReceiveProps to fetch the data if we need to.
I'll be working on a small examples and link you guys what it is. The goal here is to both be Meteor and Redux
https://medium.com/p/18a24c3b7efe
I wrote a series of posts to go over this implementation in meteor
Thank you for helping! Closing the issue as it doesn鈥檛 appear actionable for us.
Let me share how I use Meteor and Redux together.
Basically I do all reading/writing to/from Meteor in custom middleware (remember, middleware is the place where side effects can happen).
On startup, I dispatch an INITIALIZE event.
A number of custom middlewares handle INITIALIZE by performing a minimongo query inside a Tracker.autorun. Inside that autorun they use my meteor-immutable-observer to convert the results of the query into an Immutable (this is of course optional but nice if you want to optimize performance of deep views of the documents with pure render components), and then dispatch (for example) a SET_ALARM_EVENTS action with the new Immutable from my AlarmEvents collection.
There is a similar middleware for Meteor.user().
I chose to create Redux actions to wrap all Meteor methods. Whether you do this is up to you, I wanted this layer of abstraction in case we ever switch to a non-Meteor backend.
So for instance I have a custom middleware that handles an ACKNOWLEDGE_ALARM_EVENT action. It basically looks like this:
import Promise from 'bluebird';
export default store => next => action => {
next(action);
return Promise.promisify(Meteor.call)('AlarmEvents.acknowledge', action.meta.alarmIds);
};
This way, components can do:
onAcknowledgeEvents = (alarmIds) => {
this.props.dispatch(acknowledgeAlarmEvent(alarmIds))
.then(...)
.catch(...);
}
Most helpful comment
Let me share how I use Meteor and Redux together.
Basically I do all reading/writing to/from Meteor in custom middleware (remember, middleware is the place where side effects can happen).
Meteor => Redux
On startup, I dispatch an
INITIALIZEevent.A number of custom middlewares handle
INITIALIZEby performing a minimongo query inside aTracker.autorun. Inside that autorun they use my meteor-immutable-observer to convert the results of the query into an Immutable (this is of course optional but nice if you want to optimize performance of deep views of the documents with pure render components), and then dispatch (for example) aSET_ALARM_EVENTSaction with the new Immutable from myAlarmEventscollection.There is a similar middleware for
Meteor.user().Redux => Meteor
I chose to create Redux actions to wrap all Meteor methods. Whether you do this is up to you, I wanted this layer of abstraction in case we ever switch to a non-Meteor backend.
So for instance I have a custom middleware that handles an
ACKNOWLEDGE_ALARM_EVENTaction. It basically looks like this:This way, components can do: