Arkadiusz Kałkus
Arkadiusz Kałkus

Reputation: 18371

How to render React (with Redux) component only when props are received?

Let us assume we have a statefull React component (configured to work with Redux):

export class SomeComponent extends Component {
  state = {
    someObject: {}
  };

  componentWillMount() {
    this.props.getNews();
    this.props.getFakeNews();
  }

  render() {
    const {
      news,
      fakeNews
    } = this.props;

    if(_.isEmpty(news) || _.isEmpty(fakeNews)){
      return <div>Loading</div>
    }else{
      return <div>Here all component stuff</div>
    }
}

SomeComponent.propTypes = {
  news: PropTypes.array.isRequired,
  fakeNews: PropTypes.array.isRequired
};

export const Some = connect(
  state => ({
    news: newsSelectors.list(state),
    fakeNews: fakeNewsSelectors.list(state)
  }),
  {
    getNews,
    getFakeNEws
  }
)(withStyles(styles)(SomeComponent), withRouter(SomeComponent));

This component will re-render two times during getting news and fake news. In the render method we need to check if both of them are loaded.

Is there any way to trigger render only when all props are loaded?

In a perfect scenario I'd like to have no detailed null/empty check on the set of props. I believe React or Redux should perform this operation on its own as long the prop is configured as required.

Upvotes: 2

Views: 1192

Answers (4)

Vinay J Rao
Vinay J Rao

Reputation: 106

I think you can solve the issue if you rewrite the render function as below.

render() {
    const {
      news,
      fakeNews
    } = this.props;

    return (
        {news && fakeNews ? 
            <div>Here all component stuff</div>
        :   <div>Loading</div> }
    )
}

I hope this helps you.

Upvotes: 0

SM Chinna
SM Chinna

Reputation: 341

If you want to avoid null and undefined values from redux. You can use Selectors it was very easy to avoid those things.

  const newsSelectors = (state) => {

     if(!state.list) { *//list is null or undefined*
       return [] or {} *//your wish (Proptypes required value)*
     }
     else {
       return state.list
    }
 }

export { newsSelectors };

Upvotes: 0

adz5A
adz5A

Reputation: 2032

You could do something like:

// HOC factory
function ifComponent (predicate, PlaceHolder) {
  return Component => class If extends React.Component {
    render () {
      if (predicate(this.props)) {
        return <Component {...this.props} />
      }
      return <PlaceHolder {...this.props} />
      }
    }
  }
}

// create the customHOC
const whenPropsLoaded = ifComponent(props => props.news && props.fakeNews, Loader);


// compose the two HOCs using the `compose` function in redux (simple function composition)
const News = compose(
  connect(getNewsProps),
  whenPropsLoaded(DisplayNews)
);

As a side note you may be interested in the recompose utility library bad its branch HOC (docs here). I think this is pretty much what you want as you seem to know about HOCs.

Upvotes: 1

Suthan Bala
Suthan Bala

Reputation: 3299

You can add a lifecycle method `shouldComponentUpdate(nextProps, nextState).

You can add the following method and it should resolve it for you:

shouldComponentUpdate(nextProps, nextState) { 
  if (_.isEmpty(nextProps.news) || _.isEmpty(nextProps.fakeNews)) {
    return false;
  }
  return true;
}

Upvotes: 3

Related Questions