kilinkis
kilinkis

Reputation: 602

React/Redux - Why this Promise.all continues to execute after dispatch?

I have a React-Native project with redux. I perform some axios calls, and basically, the app works fine. But, there is one thing that is not right. I put a console.log before the dispatch, and even the app loads and renders everything just fine, I see the console.log looping on and on in the console. I'm not sure why this is happening, but I read the "run to completion" concept in Javascript, which can be the reason. Even though, I couldn't figure it out.

any ideas how can I fix this? thank you very much.

UPDATE: here is the component that invokes the action, in the renderEtiquetas() function. This can be the reason causing this loop, since it runs on every re-render cycle (not sure about this). I tried moving the invoke to componentDidMount() but it didn't seem to run.

I'm new to React so I'm probably doing something dumb.

component.js

class EtiquetasList extends Component {

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


  renderEtiquetas() {
    if ( this.props.etiquetas.length == 0 ) {
      return <ActivityIndicator size="large" color="#00ff00" />
    } else {
      this.props.FetchGalleries( this.props.etiquetas );
      if ( this.props.galleries.length > 0 ) {
        return this.props.etiquetas.map(etiqueta =>
          <EtiquetaDetail key={etiqueta.id} etiqueta={etiqueta} galleries={ this.props.galleries } />
        );
      }
    }
  }

  render() {
    return (
      <ScrollView>
        { this.renderEtiquetas() }
      </ScrollView>
    );

  }

}

const mapStateToProps = (state) => {

  return {
    etiquetas: state.data.etiquetas,
    isMounted: state.data.isMounted,
    galleries: state.slides.entries
  };
};

export default connect(mapStateToProps, { FetchEtiquetas, FetchGalleries })(EtiquetasList);

actions.js

export function FetchGalleries( etiquetas ) {

    return function (dispatch) {
        return Promise.all(
          etiquetas.map( record =>
            axios.get('mydomain.com/?id='+record.id)
        )).then(galleries => {

          let my_data = [];
          let data_json = '';

          galleries.map( record => {
            record.data.map( subrecord => {
              // this is simplified for this example, it works as intended
              data_json = data_json + '{ title: "' + subrecord.title+'"}';
            });

            my_data.push( data_json );

          });

        console.log( my_data ); // this keeps printing in the console
        return dispatch({ type: FETCH_GALLERIES_SUCCESS, payload: my_data });

        });
    }
}

Upvotes: 4

Views: 961

Answers (2)

AnC
AnC

Reputation: 651

You are close, you just need to return or await Promise.all otherwise it will not be awaited

export function FetchGalleries( etiquetas ) {

  return function (dispatch) {
    return Promise.all(....
  }

// UPDATE: The answer from 李骏骁 is correct

Upvotes: 1

LLL
LLL

Reputation: 581

Aha, FetchGalleries is running inside the render function, it will cause an action->render->action->render infinite loop.

Edit: How about trying to merge your FetchGalleries and FetchEtiquetas into one action:

export const fetchGalleries = () => {
  return function (dispatch) {
    return axios.get('/path/to/etiquetas').then(etiquetas => {
      dispatch({ type: FETCH_ETIQUETAS_SUCCESS, payload: etiquetas });
      // ... your previous promise all code
    });
  }
}

and only need to call this new fetchGalleries at componentDidMount.

Upvotes: 3

Related Questions