Conditional Subscriptions with React & Redux

I’m converting an app from Blaze & ReactiveDict to using React & Redux, and am interested in the best approach to subscribing to conditional publications.

Let’s say, if a user is logged-in I need to subscribe to their account data userDataHandle = Meteor.subscribe('userData') which will send down the list of books in their library, as well as the one they’re reading now. So, in this example, I need to wait until the userData is ready, then subscribe to the books publication based upon their library. Then I want to store this info in a Redux store, say Library (list of books) and Book (for their current book info), so that I can easily access this data in my React components.

My question is regarding when and where to perform these operations?

So, I’m guessing I’d put my subscription of the userData in, say, the main React createContainer layout container component, but where should the other subscriptions go since they’re dependent upon the userData? Should that happen in the Redux store upon setting a User store with the Meteor.user() data, or perhaps in the same createContainer function (after userDataHandle.ready() is true)?

Thanks!

I just realized my example above is poor since the server publication could simply look up the user’s library and current book, so it would not be dependent upon receiving a list of book _id’s.

Anyway, I’m still curious as to the best practice for the calling of subscriptions and storing of the results in regards to using Redux.

I think you can use shouldComponentUpdate to detect your update, then within the componentWillReceiveProps you can dispatch your Redux actions

I found out that you can solve this pretty easily by involving redux-thunk.

So, first you insert the thunkMiddleware in your store:

const middlewares = [
    thunkMiddleware
];

const enhancer = compose(
    applyMiddleware(...middlewares),
    //other stuff goes here like DevTools.instrument()
);

const store = createStore(rootReducer, initialState, enhancer);

Then you create an action:

export function loadUser() {
    return dispatch => {
        Tracker.autorun(() =>{
            dispatch({
                type: USER_DATA,
                data: Meteor.user()
            });
        });
    }
}

and reference that one at startup:

Meteor.startup(function(){
    render((
        <Provider store={store}>
            <Router history={history}>
                <Route path="/" component={App}>
                 </Route>
            </Router>
        </Provider>
    ),document.getElementById('root'));
    store.dispatch(loadUser());
});
3 Likes

@rhywden’s method is the closest to the ‘Redux way’ because Redux works within a functional paradigm by trying to push all side effects (tracker, meteor.call, timeout) to the edges.

This means, keeping your components as pure as possible (only props and render, not shouldComponentUpdate), keeping your reducers pure and keeping actions pure. The only places where you’d do your side effects is in action creators and in this case your async action creator.