Using Redux in Meteor/React

I’m once again exploring using Redux within Meteor/React, something that’s been a stumbling block for me before. But I’m on a project using React Native, so I decided to take another shot at Redux, and this time it clicked! (the caffeine must’ve helped…)

Anyway, I’m wondering how one goes about wiring in Mongo collections and other reactive variables into container components with Redux. Is the ReactMeteorData mixin not used? If you map Redux state to props using React-Redux’s connect:

function mapStateToProps({user}) {
  return {user}
}

export default connect(mapStateToProps)(ContainerComponent)

then does it make sense to check for Redux state changes and call dispatch within componentWillReceiveProps, since this kind of logic doesn’t belong in render?

componentWillReceiveProps(nextProps) {
  if (nextProps.user.someCondition) {
    dispatch(someReduxAction());
  }
}

render() {
  if (!this.props.user.loggedIn) {
    return <div>Log in, please!</div>
  }

  return <div> ... </div>
}

Any insight would be greatly appreciated!

Did you read Abi’s posts? https://medium.com/@abhiaiyer
It has some insights on how to approach things, maybe it’s for you, maybe not…

Have you checked Adam’s flux-helpers? https://github.com/AdamBrodzinski/meteor-flux-helpers
I keep referring back to it, because it’s really easy to begin with things and think about possible problems later (I mean, it’s easy to get a proof of concept running, don’t worry about the redux store vs minimongo). Maybe @SkinnyGeek1010 has some tips as well, since he has experience with React Native also if I’m not mistaken.

What is the use case? Maybe you don’t even need de lifecycle hooks in this case? Perhaps something else can call the action for example?

Also, but it’s more a personal preference, I like to move dispatch actions to props as well, with mapDispatchToProps from react-redux. This way you even more decouple redux with the components.

1 Like

It sounds like you want to cause a side effect. In that case you should probably use redux thunk instead.

In simple apps I just let Minimongo take care of data and use getMeteorData for mongo data and Redux for everything else.

However, it can be helpful to have all data in one tree as it can be more simple to keep track in your head. The easiest way i’ve found is to use the flux helpers I made and dispatch a ‘collection changed’ event. Then you basically just read from the collection and return that as the new state. In essence you’re just mirroring Minimongo whenever it changes it’s data. This means you never have to worry about manually updating/removing/inserting data… it just works.

There is a memory cost to this of course and it can make your Redux more complicated (by just a bit). I just have a collections reducer that switches on the collection name and they sync data. I also have a viewer collection that basically watches Meteor.user()

Here’s the gist (from the package):

 Tracker.autorun(computation => {
    var docs = Players.find({}).fetch();

    if (computation.firstRun) return; // ignore first empty run

    CollectionActions.playersChanged(docs);
  });
3 Likes

Ok. But on a very basic level, I was just wondering: if getMeteorData is the place one listens for changes in Mongo collections and ReactiveDicts, then where does one listen to changes in the Redux state? Of course render is the place if it’s determining whether to display something or not based on Redux state. But what about when you want to dispatch an action? That’s why I figured componentWillReceiveProps might make sense, since Redux state changes come into the React container in the form of props.

I’ll check those in detail now, thanks!

Ah yes, componentWillReceiveProps looks like a good place to have business logic respond to Redux state changes:

  componentWillReceiveProps(nextProps) {
    if (nextProps.forPerson !== this.props.forPerson) {
      this.props.dispatch(
        makeASandwichWithSecretSauce(nextProps.forPerson)
      );
    }
  }

redux-thunk looks like what I’m looking for. Thanks!

1 Like

So just to recap to make sure I understand this:

Action creators should only return an action object of format {type: 'SOME_ACTION'[, ...other properties]}, and shouldn’t perform any actions such as fetch(), db operations, etc. For that, use a thunk?

export function thunkAction() {
  return () => {
    doSomething();
  }
}

Does a thunk need to return an action object as well? How would you go about doing that, like this?

export function thunkAction() {
  return () => {
    doSomething();

    return {
      type: 'SOME_ACTION'
    }
  }
}

lets say you have a function and within the function and you need to use dispatch from redux to update some actions, something like this

const verifySomething=(arg1,arg2)=>{
  if(arg1, arg2)
    dispatch(action1)
  else
   dispatch(action2)
}

so you need the dispatch from somewhere
without using the thrunk, you can do something like following

const higherOrderWrapper=(dispatch)=>{
 return(arg1,arg2)=>{
   if(arg1, arg2)
     dispatch(action1)
   else
     dispatch(action2)
 }
} 

(PS:you have to call this one like higherOrderWrapper(dispatch) )

then you call higherOrderWrapper with the dispatch from the connet or the store.dispatch

else if you use ‘thrunk’(just reverse the order)

const higherOrderWrapper=(arg1,arg2)=>{
 return(dispatch)=>{
   if(arg1, arg2)
     dispatch(action1)
   else
     dispatch(action2)
 }

}

you can call it like dispatch(higherOrderWrapper)

Hope this help

Redux-Thunk provides you dispatch and getState to use in the returning function:

export function simpleAction() {
  return {
     type: "SOME ACTION"
  }
}


export function thunkAction() {

  return (dispatch, getState) => {
   Meteor.call((error, res)=>{
     dispatch(simpleAction());
   })    
  }

}

Some tips:

  1. dispatch not only can dispatch other actions but also other thunk actions as well
  2. getState is a function not a variable, because you want to make sure you have the latest state, if you are dispatching AFTER a remote call, the state might have changed since the start of the call, and if you want to dispatch depending on the currents state, you should do
    const state = getState();

You don’t have to return anything in a thunk.

Typically, you use thunks to handle asynchronous things like Meteor methods or ajax calls, etc.

What happens to the Optimistic UI Meteor offers if we do asynchronous calls? Doesn’t it cause delay on the UI because of waiting for the result to arrive?