Rory
Rory

Reputation: 1492

React / Redux wait for store to update

I have a problem that a react component is rendering before the redux store has any data.

The problem is caused by the React component being rendered to the page before the existing angular app has dispatched the data to the store. I cannot alter the order of the rendering or anything like that.

My simple React component is

import React, {Component} from 'react';
import { connect } from 'react-redux';

import {addBot} from './actions';

class FlowsContainer extends React.Component {

  componentDidMount() {
      this.props.initStoreWithBot();
  }

  render() {
    // *** at this point I have the store in state prop
    //but editorFlow array is not yet instanced, it's undefined

    const tasks = this.props.state.editorFlow[0].flow.tasks
    return (
          <div>      
              Flow editor react component in main container          
          </div>
      );
  }

}

const mapStateToProps = (state) => ({
  state : state
})

const mapDispatchToProps = (dispatch) => {
    return {
        initStoreWithBot : () => dispatch(addBot("test 123"))
    };
};

export default  connect(
  mapStateToProps,
  mapDispatchToProps
)(FlowsContainer)

So how can I hold off the rendering until editorFlow array has elements ?

Upvotes: 5

Views: 9918

Answers (3)

Rory
Rory

Reputation: 1492

In response to Cssko (I've upped your answer) (and thedude) thanks guys a working solution is

import React, {Component} from 'react';
import { connect } from 'react-redux';

import {addBot} from './actions';

class FlowsContainer extends React.Component {

  componentDidMount() {
      this.props.initStoreWithBot();
  }

   render() {
    const { editorFlow } = this.props.state;
    let tasks;
    if (typeof editorFlow === 'object' && editorFlow.length > 0) {
        tasks = editorFlow[0].flow.tasks;
    }

    if(tasks){
        return (
          <div>      
              Flow editor react component in main container          
          </div>
        )
      }
      else{
          return null;
      }
  }
}

const mapStateToProps = (state) => ({
  state : state
})

const mapDispatchToProps = (dispatch) => {
    return {
        initStoreWithBot : () => dispatch(addBot("test 123"))
    };
};

export default  connect(
  mapStateToProps,
  mapDispatchToProps
)(FlowsContainer)

Upvotes: 0

cssko
cssko

Reputation: 3045

You can use Conditional Rendering.

import {addBot} from './actions';

class FlowsContainer extends React.Component {

  componentDidMount() {
      this.props.initStoreWithBot();
  }

  render() {
    // *** at this point I have the store in state prop
    //but editorFlow array is not yet instanced, it's undefined

    const { editorFlow } = this.props.state;
    let tasks;
    if (typeof editorFlow === 'object' && editorFlow.length > 0) {
        tasks = editorFlow[0].flow.tasks;
    }
    return (
      {tasks && 
          <div>      
              Flow editor react component in main container          
          </div>
      }
      );
  }

}

const mapStateToProps = (state) => ({
  state : state
})

const mapDispatchToProps = (dispatch) => {
    return {
        initStoreWithBot : () => dispatch(addBot("test 123"))
    };
};

export default  connect(
  mapStateToProps,
  mapDispatchToProps
)(FlowsContainer)

Upvotes: 3

Patrick
Patrick

Reputation: 3367

As far as I know, you can't.

the way redux works is that it first renders everything, then actions take place with some async stuff(such as loading data), then the store gets populated, and then redux updates the components with the new state(using mapStateToProps).

the lifecycle as I understand it is this :

  1. render the component with the initial state tree that's provided when you create the store.
  2. Do async actions, load data, extend/modify the redux state
  3. Redux updates your components with the new state.

I don't think mapping the entire redux state to a single prop is a good idea, the component should really take what it needs from the global state.

Adding some sane defaults to your component can ensure that a "loading" spinner is displayed until the data is fetched.

Upvotes: 3

Related Questions