Skip to content
This repository has been archived by the owner on Dec 24, 2019. It is now read-only.

How to chain action Promise #66

Open
govind999 opened this issue Sep 30, 2016 · 13 comments
Open

How to chain action Promise #66

govind999 opened this issue Sep 30, 2016 · 13 comments

Comments

@govind999
Copy link

govind999 commented Sep 30, 2016

Hi Team,

I am following your code boilerplate for my project, I ran into a situation where i am making an API call which responds with xml data, so i need to parse that data and then send to reducer. May i know how to do that.

// first the api call has to be made,
export function getTodos() {
  return {
    type:    'GET_TODOS',
    promise: request.get(API_URL)
  }
}
then it need to parse the response

// using https://github.com/Leonidas-from-XIV/node-xml2js
 parseString(res, function (err, result) {
  // data gets parsed here
});

Then it has to send the raise the event. I tried as below but it is throwing error

const request = axios.get(url).then(res=>{
        parseString(res, function (err, result) {
           if(result){
                dispatch({
                   type: GET_TODOS,
                   data:result
                })
            }
            if(err) throw err
        });
    }).catch(err=>console.error(error))
};

I am getting below error

Error: Actions must be plain objects. Use custom middleware for async actions.

Thanks.

@bananaoomarang
Copy link
Owner

If you don't have control over the parseString function and don't want to introduce a Promise 'polyfill' library and use a promisify function, you could do something like:

const request = axios.get(url).then(res => {

    return (new Promise((resolve, reject) => {

        parseString(res, function (err, result) {
            if(err) return reject(err)

            return resolve(result)
        })

    })

})

I'll admit I'm unclear on the code, exactly. But you might want to do something like:

dispatch(createMyFirstAsyncPromiseAction())
    .then((success) => {
        if(success) return dispatch(createMySecondAsyncPromiseAction())
    })

Though I would probably discourage this coupling/chaining of actions and consider consolidating into one action. If you really want this complication redux-saga is pretty great.

That error means you're triggering a dispatch of a non-object somewhere, likely in a middleware.

Redux thunk also exists, and there's no reason you can't use it alongside the Promise middleware included here, or switch to i entirely. IMO it can get a little messy/hard to read, but it is very flexible.

@govind999
Copy link
Author

Thanks for the answer, yeah it is asyn operation, that is the reason. Do you suggest changing from promiseMiddleware to redux saga or thunk? is it easy to change that in your code? do you suggest that way, because i am using your code as boilerplate and project is up and running.

@bananaoomarang
Copy link
Owner

I personally prefer writing promise middleware to thunk, and as long as you understand the code you can really extend it to do whatever you want. If you look at saga or thunk and like either you can start using them.

For this case though any of my above solutions should work fine, you can chain async actions with the promise middleware as in the last example. I would just say that if you're chaining a bunch of actions you should think about refactoring them, because coupling actions isn't a really a desirable pattern.

That said I would always advocate your better judgment! Don't worry so much about the implementation, worry that you understand it, are comfortable working with and extending it etc.

To be clear, the first example above is to combine these things into one action (ie, if they will always be run in sequence) and to adapt the callback code to a promise. The second example is how to do it without much refactoring, just dispatch and use use then to dispatch another action after.

@govind999
Copy link
Author

Thanks @bananaoomarang , i liked both your solutions, let me try now.

@govind999
Copy link
Author

govind999 commented Sep 30, 2016

i will change the code like this, do you agree

export function getSearcData() {

  const request = axios.get(API_URL).then(res => {

    return (new Promise((resolve, reject) => {

        parseString(res, function (err, result) {
            if(err) return reject(err)
            return resolve(result)
        })

    })
  })     

  return {
    type:    'GET_DATA_XML_API',
    promise: request
  }

@bananaoomarang
Copy link
Owner

That looks good to me

@govind999
Copy link
Author

Works like a charm, thank you. I know this is more like issues forum, if i want to ask you questions in future, what is best place to reach you?

@bananaoomarang
Copy link
Owner

This works fine for me (though I can’t promise quick replies)

I think my email is on my Github profile page too? If not you can just use
here.

On Fri, 30 Sep 2016, 15:34 govind999, notifications@github.com wrote:

Works like a charm, thank you. I know this is more like issues forum, if i
want to ask you questions in future, what is best place to reach you?


You are receiving this because you were mentioned.

Reply to this email directly, view it on GitHub
#66 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAxy12xf0GBd7MRpnoBXm_NujJwXInV2ks5qvWRKgaJpZM4KKzka
.

@govind999
Copy link
Author

Just one more question, as it is rawHTML, i am planning to get it from store.getState().RawHTMLdata and pass to template of HTML. Because the HTML is in state its messing up UI. How can use and then delete it from store before i send it to UI? any ideas?

@bananaoomarang
Copy link
Owner

Not sure what you mean by this.

Maybe you want: https://facebook.github.io/react/tips/dangerously-set-inner-html.html

@govind999
Copy link
Author

What i mean to say is when the reducer has HTML data, it will go to store and then go UI as initial state right? so its rawHTML and is messing up UI. I thought i will grab the HTML from store and then send to template and delete it from store before sending to store, i posted on stack overflow too..

http://stackoverflow.com/questions/39799728/delete-one-reducer-data-from-store-before-rendering

@bananaoomarang
Copy link
Owner

Hmmm, I wouldn't necessarily advise putting HTML in the store but AFAIK no reason you shouldn't be able to. The initialState passed from the backend is just a serialized, JSON string so you should be have runs of HTML in there.

Are you seeing errors in the console or are you just unable to display it? If it's the latter you probably just have to signal you want it to be displayed as HTML and not text.

As I say, no technical reason you can't do this, but you might want to consider if it's the best approach.

@govind999
Copy link
Author

If i keep the HTML in the store, the initial state which goes to UI has this data. So the html is getting printed on the page from store object as they are HTML tags, So want i did is, i manually removed that html from initial state.

  const initialState = store.getState();

const HTMLstr = '<!doctype html>' +
renderToString();
return HTMLstr;

       <script dangerouslySetInnerHTML={{__html: `window.__CONFIG__ =${JSON.stringify(config)};`}} charSet="UTF-8"/>

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants