Hamed Minaee
Hamed Minaee

Reputation: 2560

ajax call loads after rendering happens

I am new to react and redux and I am facing a very strange issue. I have an action as follows:

export function getStorySnippetsAction(snippetsLink, channel) {

return dispatch => {
    let storiesSnoppet = [];

    for (var i = 0; i < snippetsLink.length; i++) {

        $.ajax({
            url: snippetsLink[i],
            dataType: 'json',
            cache: false,
            success: function (data) {
                storiesSnoppet.push(data);
                console.log("xxxxxxxxxxxxxxxxxxxxx");
                console.log(storiesSnoppet);

            }.bind(this)
        });
    }


    dispatch({
        type: "SET_STORY_SNIPPET",
        payload: {"channel": channel, "storiesSnippet": storiesSnoppet}

    });

};

}

As you can see I have some ajax calls in a loop and then I use dispach to set state. Now my problem is ajax calls are asynchronous so when ajax sends request the dispach happens and does not wait for all ajax call to finish. Also the following is what I get when I print out the payload.action in console:

console log

As you can see when the object is collapsed it has a size of 0 and when I expand it I can see some objects in an arraylist. My only guess for such a strange behavior is that the asynch call complete after the rendering and since componentdidmount( which I call getStorySnippetsAction in it) happens just once the rerender does not happen again and I do not see any result. Someone told be to put my call to getStorySnippetsAction inside componentdidupdate but when I do that then it seems that an infinite loop happens and the page never loads ( I can see that in the console the same thing is written again and gain which means that component did update invokes infinitely). Now I am totally stuck. If I call getStorySnippetsAction in componentdDidUpdate I will be in an infinite loop and if I call it in componentDidMount ajax takes longer that rendering and rendering happens with empty array instead of loading the ajax result.

Can anyone help? (Even an idea may help me to fix this issue. Thanks a million)

Upvotes: 0

Views: 108

Answers (2)

Cheng Sieu Ly
Cheng Sieu Ly

Reputation: 1166

The idea here is that you turn each request into a Promise and store it in an array. Once each request finishes, we will resolve it with the data. Finally, once all the promises in the array are resolved, then we call dispatch with the resolved values.

export function getStorySnippetsAction(snippetsLink, channel) {

  return dispatch => {
    let storiesSnoppet = [];

    for (var i = 0; i < snippetsLink.length; i++) {
      storiesSnoppet.push(new Promise((resolve, reject) => {
        $.ajax({
          url: snippetsLink[i],
          dataType: 'json',
          cache: false,
          success: function(data) {
            resolve(data);
            console.log("xxxxxxxxxxxxxxxxxxxxx");
            console.log(storiesSnoppet);
          }.bind(this)
        });
      }));
    }

    Promise.all(storiesSnoppet).then((values) => {
      dispatch({
        type: "SET_STORY_SNIPPET",
        payload: {
          "channel": channel,
          "storiesSnippet": values
        }
      });
    });
  };
}

Upvotes: 1

Robsonsjre
Robsonsjre

Reputation: 1606

Why dont you put your dispatch after a callback from async module instead of for loop?

Example:

import parallel from 'async/parallel'
export function getStorySnippetsAction(snippetsLink, channel) {

return dispatch => {
    let storiesSnoppet = [];
    const ajaxFunctionArray = snippetsLink.map(i => {
      return function(callback) {
        $.ajax({
            url: snippetsLink[i],
            dataType: 'json',
            cache: false,
            success: function (data) {
                storiesSnoppet.push(data);
                callback(null)
                console.log("xxxxxxxxxxxxxxxxxxxxx");
                console.log(storiesSnoppet);
            }.bind(this)
        });
      })
    //it ill make the posts in parallel and them dispatch just after all have finished

    async.parallel(ajaxFunctionArray, function (err, result) {
      dispatch({
        type: "SET_STORY_SNIPPET",
        payload: {"channel": channel, "storiesSnippet": storiesSnoppet}

    });   
    }

};

Upvotes: 1

Related Questions