Need to figure out this Redux & getMeteorData() issue

Hey, I just started using React and Redux in Meteor 1.2. I’m using Redux for state management and one of its function is setting the screen name for each screen. The rootApp component is responsible for setting the screen name from mapping state to props via connect().

So I set it up that in each screen container component, the dispatch function will pass an action to ask the rootApp to set the screen name. So here’s my issue… For one of the screens, I want to get the name of the screen from a collection. I got everything working except for setting the screen name. I set the dispatch function in the componentDidMount(), but the screen name came up undefined.

I checked the other React Component APIs , such as componentWillUpdate(), componentDidUpdate(), and componentWillMount(). None of them will work. I even tried in the render(), but it threw an error at me.

I think the issue is that the dispatch function is firing before the collection is ready. What’s the best practice for getting data from a collection first and dispatching it on screen load?

Here’s the code for reference:

event.jsx:

getMeteorData() {
  const { event_id } = this.props;
  const eventSub = Meteor.subscribe('events.single', Number(event_id));
  return {
    eventReady: eventSub.ready(),
    event: events.find({}).fetch()
  };
}

componentDidMount() {
  const { dispatch } = this.props;
  const { event, eventReady } = this.data;
  if(eventReady) dispatch({ type: 'SET_SCREEN_NAME', screen_name: event.base_title });
}

rootApp.jsx

getScreenName() {
  const { screen_name } = this.props;
  return screen_name;
}

render() {
  return(
    <div className="app-root">
      {this.props.nav || <AppHeader hasUser={this.data.hasUser} />}
        <div className="container">
          <div className="panel panel-default panel-custom">
            <div className="panel-heading panel-heading-custom">
              <h3>{this.getScreenName()}</h3>
            </div>
            <div className="panel-body">
              {this.props.yield}
            </div>
          </div>		 
        </div>
        {this.props.footer || <AppFooter />}
      </div>
    );
}

const mapStateToProps = (state) => {
  return {
    screen_name: state.Screen.screen_name
  }
};

App = connect(mapStateToProps)(App);

I suggest nesting this dispatch logic one component below the root component. that way you forsure have all the data you need.

Hi,

what happens if you console.log eventReady in componentWillUpdate?

also aren’t u trying to fetch before the sub is ready?

I’m quite new to this so sorry if I’m way off

That’s what I ended up doing. However I’ve decided to upgrade to 1.3 and rewriting the state management logic that makes sense.

Don’t be sorry! We all were new to this at some point :slight_smile:. Asking questions is good.

Yeah I thought about putting it in the componentWillUpdate, but the problem is it will re-fetch the screen name everytime the page re-render on each update. Also there will be a discernible delay before the screen name switch from blank to the page name between initial page render and the first update.

As for your last question, doing it this way is a quite common pattern in Meteor and React architecture:

getMeteorData() {
  const { event_id } = this.props;
  const eventSub = Meteor.subscribe('events.single', Number(event_id));
  return {
    eventReady: eventSub.ready(),
    event: events.find({}).fetch()
  };
}

In a sense, you are right that I am ‘fetching’ before it’s ready; I created an handle called eventReady that gets a return boolean value from Meteor.subscribe that is true when it’s finished subscribing to the subs and event is a placeholder for the subs once they is ready. However if I try to access this.data.event in the render() section before eventReady is true, it will throw an error and say that ‘event’ is undefined. That’s why I added an if-statement to check if eventReady is true before I try to access ‘event’, like this:

if(eventReady) dispatch({ type: 'SET_SCREEN_NAME', screen_name: event.base_title });

eventReady is useful for showing a loading indicator or doing some state management routines.

according to the old doc, this.data is not the same as this.state when you try to manage the component state. In your case, you might want to pass this.data down to a child component, and let the child component utilize the this.props in both componentDidMount and componentDidUpdate those two areas

Yup, that’s the approach I’m thinking of taking when I upgrade to 1.3 and rewriting the app. I’ll be following the example from here: ffx-meteor-react-boilerplate

@craigcannon you’ve probably seen all of these articles before, but I made a list of all the helpful Meteor specific Redux stuff I found as part of getting up to speed with using Redux in Meteor here: https://github.com/tomRedox/simpleCRM#redux-in-meteor---the-path-to-enlightenment.

If you haven’t already come across the container pattern and the various implementations of it then the articles listed here are worth reading too: https://github.com/tomRedox/simpleCRM/blob/master/README.md#react-in-meteor

The repo those links are in is a worked example of using Redux in Meteor.

1 Like

That looks like a great resource! I haven’t read half of those yet. Bookmarked!

1 Like