ChatGPT解决这个技术问题 Extra ChatGPT

return promise from store after redux thunk dispatch

I am trying to chain dispatches with redux thunk

function simple_action(){
  return {type: "SIMPLE_ACTION"}
}

export function async_action(){
  return function(dispatch, getState){
    return dispatch(simple_action).then(()=>{...});
  }
}

How do I get the dispatch to return a promise from the store?

MORE SPECIFICALLY:

I am probably just not understanding something here, but in all the examples with redux-thunk, they call a separate async event (like fetch), which obviously returns a Promise.

What I'm specifically looking for is when I dispatch an action to the store: How do I make certain the store has processed that action completely before anything else happens in the function action_creator() above.

Ideally, I would like the store to return some sort of promise, but I don't understand how or where that happens?


A
Aaleks

Here you have an example on how to dispatch and chain async action. https://github.com/gaearon/redux-thunk

The thunk middleware knows how to turn thunk async actions into actions, so you just have to have your simple_action() to be a thunk and the thunk middleware will do the job for you, if the middleware see a normal action, he will dispatch this action as normal action but if it's an async function it will turn your async action into normal action.

So your simple_action need to be a thunk ( A thunk is a function that returns a function.) Like this for example:

function makeASandwichWithSecretSauce(forPerson) {
  return function (dispatch) {
    return fetchSecretSauce().then(
      sauce => dispatch(makeASandwich(forPerson, sauce)),
      error => dispatch(apologize('The Sandwich Shop', forPerson, error))
    );
  };
}

When using the makeASandwichWithSecretSauce function you can use the dispatch function

store.dispatch(
  makeASandwichWithSecretSauce('Me')
);

And even

// It even takes care to return the thunk’s return value
// from the dispatch, so I can chain Promises as long as I return them.

store.dispatch(
  makeASandwichWithSecretSauce('My wife')
).then(() => {
  console.log('Done!');
});

Here a complete example on how you can write action creators that dispatch actions and async actions from other action creators, and build your control flow with Promises.

function makeSandwichesForEverybody() {
  return function (dispatch, getState) {
    if (!getState().sandwiches.isShopOpen) {
      // You don’t have to return Promises, but it’s a handy convention
      // so the caller can always call .then() on async dispatch result.
      return Promise.resolve();
    }

    //Do this action before starting the next one below 
    dispatch(simple_action());

    // We can dispatch both plain object actions and other thunks,
    // which lets us compose the asynchronous actions in a single flow.
    return dispatch(
      makeASandwichWithSecretSauce('My Grandma')
    ).then(() =>
      Promise.all([
        dispatch(makeASandwichWithSecretSauce('Me')),
        dispatch(makeASandwichWithSecretSauce('My wife'))
      ])
    ).then(() =>
      dispatch(makeASandwichWithSecretSauce('Our kids'))
    ).then(() =>
      dispatch(getState().myMoney > 42 ?
        withdrawMoney(42) :
        apologize('Me', 'The Sandwich Shop')
      )
    );
  };
}
//apologize and withdrawMoney are simple action like this for example
      return {
        type:  "END_SUCESS"
      }

//usage

store.dispatch(
  makeSandwichesForEverybody()
).then(() =>
    console.log("Done !");
);

To create you own promises you can use a library like bluebird.

//EDIT : To be sure that the store has processed that action completely before anything else happens in the function action_creator() you can dispatch this simple_action before action_creator(); // I added this comment to the code //Do this action before starting the next one below


For me this isn't working. If I want to call then after store.dispatch() I get a TypeError: Cannot read property 'then' of undefined. My action definitely returns a promise.
did you register the tune middleware ? github.com/gaearon/redux-thunk Installation section
did you register the thunk middleware ? Can you provide some code to see where the problem might be ?
Issue is solved. Dan Abramov pointed out that using setTimeout won't be working and in Angular I simply missed to return dispatch in my store wrapper. Thanks for your help and time anyway.
This answer is plagiarized almost verbatim from Facebooks example. At the very least attribution should be given, or this answer removed.
M
Mapsy

This is a pattern I've been using recently:

export const someThenableThunk = someData => (dispatch, getState) => Promise.resolve().then(() => {
  const { someReducer } = getState();
  return dispatch({
    type: actionTypes.SOME_ACTION_TYPE,
    someData,
  });
});

When you dispatch(someThenableThunk('hello-world')), it returns a Promise object that you can chain further actions to.


interesting +1 technique.
simple and powerful
Fantastic, and exactly what I needed.. out of curiosity, are there any downsides to this pattern?
@JohnDetlefs Awesome! Not that I've found. It's likely less performant than synchronous solutions. I use it basically everywhere. It helps enforce a common convention I use now, where state modifiers (i.e. actions) are specifically promises and state analysis are conventional synchronous getters. This way it helps enforce separation and consistency.
@Mapsy - Ta for the followup, love that pattern, I suspect I'll be using a lot from now on. 👍
D
Darren Shewry

dispatch will return whatever the action/function it calls returns; so if you want to chain certain activities (as per your example), your action would need to return a Promise.

As @Aaleks mentions, if your action were a thunk you can create a scenario where you return a Promise, then you could do as you mention.

BTW I think naming your thunk action_creator is a bit misleading, as simple_action is actually an Action Creator in Redux parlance - have edited accordingly :)


t
technik

What you will need to do is create trunkate action which returns Promise. The dispatch function return what you have added as argument to it's call. For example, if you want dispatch to return Promise you'd have to add Promise as argument to the call.

function simple_action() {
  return { type: 'SIMPLE_ACTION' };
}

export function async_action(dispatch, getState) {
  return function () {
    return Promise.resolve(dispatch(simple_action()));
  }
}

const boundAction = async_action(dispatch, getState);
boundAction().then(() => {});

We have the same approach due to simplicity in implementation. You can either return Promise resolve or reject and let the caller do a then for resolve, catch for reject -- which for me maintains the chain. At the same time, you are returning the dispatch object containing possible payload from api. But, not sure if this conforms to best practices. Anyone? I kinda don't like the idea that the caller will handle success/failure inside then(). Failure should be handled in catch.