First of 3 blog posts going over a Meteor and Redux integration we use here at Workpop. This part just goes over the concept of Domain State and UI State. Also I’ve included tons of introductory material in learning Redux so you’ll be ready for part 2!
A huge misconception in Meteor-Redux implementations is the belief that ALL of your state goes into a Redux store.
I’m afraid I might be responsible for this one When providing Redux examples most of my apps stored everything in Mongo. However, my main reason was because I wanted to de-couple from Meteor, at the extra cost of memory and wiring… which isn’t an issue for a lot of apps.
Thanks for the write up, looking forward to Part 2. We need more of these articles cause I’ve been fumbling around trying to piece this together myself.
Both you and @SkinnyGeek1010 have mentioned that redux is for UI state and Domain state should be managed elsewhere, e.g in Minimongo. However, this means that your container components are not pure (FilterLink and TodoList) because they contain side effects in getMeteorData(). This makes the components harder to test because you’d have to mock out Meteor.subscribe in this particular instance.
My concern here is that there may be alot more of these ‘smart’ components that depends on subscriptions (one for every collection at least?).
However, if you were to remove getMeteorData() and pass data only by props through the redux store (UI & Domain states) then all components will be pure and test friendly (pure components is one of the core ideas that attracted me to redux).
In getMeteorData’s place, use Tracker to dispatch actions when any collection has updated (e.g store it in state.db.collections) and this will trigger any pure components that need to re-render since their props changed.
The only bad thing AFAIK is that it duplicates the data in minimongo and in the store.
Why isn’t this a good idea? And why is putting side effects into smart container components better?
Give.
I can’t tell you how happy articles like this make me right now. I feel like I’m stuck between React and Blaze and a series of articles like this give me hope… it’s great to look forward and not dwell on the current state too much.
Yep, that’s why I don’t unit/integrate test them I’ll cover these with end to end tests since those will overlap with an integration test.
However, if you were to remove getMeteorData() and pass data only by props through the redux store (UI & Domain states) then all components will be pure and test friendly
I still have a ‘smart component’ to subscribe to data (though you wouldn’t have to, you could break it out somewhere else). I guess the most decoupled from the UI is to have the UI trigger an action that just subscribes or something.
In getMeteorData’s place, use Tracker to dispatch actions when any collection has updated (e.g store it in state.db.collections) and this will trigger any pure components that need to re-render since their props changed.
The only bad thing AFAIK is that it duplicates the data in minimongo and in the store.
Why isn’t this a good idea? And why is putting side effects into smart container components better?
This is how I do it as well (with the flux helpers package), I don’t care for getMeteorData and am willing to pay the extra time to wire it up and to have all data in one place.
Yeah, my Domain State container components are not pure. And I am okay with that. I’ve used Meteor for awhile and can both explain how Tracker works and its pitfalls to my team. You’re right, though! It is tough to test due to the mocking of Meteor.subscribe but it’s okay to mock it out. I usually unit test my actions, and E2E this type of stuff. Even if there are tons of collections I’ll eat the cost in testing them. It’s just very convenient to manage state this way that it’s worth the hassles in downstream activities.
What you suggested is cool! I like it, just something I didn’t do. I didn’t want to duplicate state in 2 stores. I don’t think there is one OFFICIAL good way…just ways that people can support and reason easier. If you find it easier to do what you described go for it!