(learning) how to prevent functions from running before db loading with react extend component?


#1

hello everyone, i’m having trouble with how to correctly write functions and display data in react components because sometimes they write before the user data has been loaded from database, so if for example i want to run something like this:

  render() {
    return (Meteor.user() && !Meteor.user().emails[0].verified) ? (text to say verify) : (actual component data)

it isn’t constant

or if for example i want to display a const based on the e-mail address i get an error that says it can’t retrieve emails properties from object.

i’ve read some help but it is for blaze with it’s onLoad function, or even using react createclass but i’m using the new syntax react extend component so i don’t know what the equivalent would be

thanks in advance for your help to this newbie !!


#2

Hi,

There is a couple of ways to handle this. Basically, (a) use React life cycle helpers like componentWillMount() and componentWillReact(); (b) do the work in the component above it and send in the result of the function as a prop; © Use a store in a higher level component which has all this information. Then the lower end component will receive it as a prop. This can be made reactive downstream. (d) The store is actually a publication itself, and stuff changes downstream re-actively as the store is a publication.

I’d recommend you start out with componentWillMount() type solutions. Then, you can move to store type solutions depending on what you are comfortable with for managing state - options b and c above. In certain circumstances, d can also be useful, but this is generally a pattern I use for user related functionality only. Depends on your use case.

Thanks so much.

Tat


#3

Hi,

The above can be expanded on I guess. In the below, an example of ©:

import React, { Component, PropTypes } from 'react';
import { observer } from 'mobx-react'; // using MobX to manage state as opposed to setState...

import FlatButton from 'material-ui/FlatButton'; // using material ui...

@observer // there are no observables as this is a
// lower component. A higher component handles an 
// observable store.
export class RootPath extends Component {
  // a standard function all my components have. Basically 
  // I pass it in as a prop so any component downstream can 
  // manipulate the store up top. 
  // Note: this is not best practise. I have done it this way so I can pull it out later
  // and load it from another location, where I will put in tests; once the functionality is done.
  handleOutput(toChange, newValue) {
    this.props.output(toChange, newValue);
  }

  handleTouchTap() {
    this.handleOutput('groupSelection', ''); // so onTouchTap event, 
    this.handleOutput('entitySelection', ''); // do some stuff to manipulate
    this.handleOutput('paneSelection', 'entityAdmin'); // the store...

  }

  render() {
    const styles = {
      path: {
        margin: '5px',
      },
    };

    if (this.props.selections.entitySelection.length > 0) {
      return (
        <span>
          <FlatButton
            style={styles.path}
            label="Sales"
            onTouchTap={this.handleTouchTap.bind(this)}
          /> >
        </span>
      );
    }

    return (
      <FlatButton
        style={styles.path}
        label="Sales"
        disabled={true}
      />
    );
  }
}

RootPath.propTypes = {
  selections: PropTypes.object.isRequired, // the store I am using
  output: PropTypes.func.isRequired, // func to manipulate the store contents...
};

So, in the above, there is no need for componentWillMount as the component looks at the store prop to work out what to do. Because the store prop is an observable object, any change causes a re render of whatever is dependent on it. This is using mobX to manage state…

If we were using this.setState and not mobX; in essence, it would look something like below. Note this is without a store, as if it is independent. The componentWillMount runs before the component is mounted for the first time. To make this reactive, we would tell the component to expect props using similar lifecycle methods. :

import React, { Component, PropTypes } from 'react';

import FlatButton from 'material-ui/FlatButton';

export class RootPath extends Component {
  // We would need a constructor here
  // This would initialize a bunch of states

  // Here we would need something like:
  // componentWillMount() {
  // this.setState = whatever...
  // }

  // Other functions to manage various state mutations...

  handleTouchTap() {
    // do some state mutations or call some functionality...
  }

  render() {
    const styles = {
      path: {
        margin: '5px',
      },
    };

    if (this.props.selections.entitySelection.length > 0) {
      return (
        <span>
          <FlatButton
            style={styles.path}
            label="Sales"
            onTouchTap={this.handleTouchTap.bind(this)}
          /> >
        </span>
      );
    }

    return (
      <FlatButton
        style={styles.path}
        label="Sales"
        disabled={true}
      />
    );
  }
}

RootPath.propTypes = {
  selections: PropTypes.object.isRequired,
  output: PropTypes.func.isRequired,
};

Thanks so much.

Tat

tl,dr: use componentWillMount() to simulate onLoad…


#4

thanks for pointing me to the right path my friend