Redux Thunk - Why do I have to call dispatch() twice?

Redux Thunk - Why do I have to call dispatch() twice?



Note I'm calling setStepPositionIndex() with dispatch(). When I remove dispatch(...) to become just setStepPositionIndex()
I would expect that the dispatch call within setStepPositionIndex() would receive the plain action object it's passed and dispatch it...


setStepPositionIndex()


dispatch()


dispatch(...)


setStepPositionIndex()


setStepPositionIndex()



Alternatively, if I remove the dispatch() call within setStepPositionIndex() (and keep dispatch(setStepPositionIndex()) while explicitly returning plain actionObj within it, I would expect a successful dispatch with dispatch(setStepPositionIndex(actionObj))


dispatch()


setStepPositionIndex()


dispatch(setStepPositionIndex()


actionObj


dispatch(setStepPositionIndex(actionObj))



But yet successful execution of this action creator requires both... why?


/* actions.js */
import store from "../store.js";

store.dispatch(setStepPositionIndex());

export const SET_STEP_POSITION_INDEX = "SET_STEP_POSITION_INDEX";
export const setStepPositionIndex = () =>
return (dispatch, getState) =>
const newSteps = getState().goals.currentGoalSteps.map((stepObj, index) =>
return ...stepObj, positionIndex: index ;
);
console.log("newSteps", newSteps);
/* [step: "Step3", positionIndex: 0
step: "Step2", positionIndex: 1
step: "Step1", positionIndex: 2] */

const actionObj =
type: SET_STEP_POSITION_INDEX,
stepsArr: newSteps
;
// Unsuccessful alone ->
// return actionObj

// unsuccessful alone (removing dispatch() wrapper from setStepPositionIndex
//->
return dispatch(actionObj);
;
;

/*Reducer.js*/

import * as actions from "../Actions/actions";
import store from "../store";
if (action.type === "SET_STEP_POSITION_INDEX")
return update(state,
currentGoalSteps: $set: action.stepsArr
);


/*Store.js */
import createStore, applyMiddleware, compose, combineReducers from "redux";
import ApolloClient from "react-apollo";
import createLogger from "redux-logger";
import reducer as formReducer from "redux-form";
// import client from './index'
import thunk from "redux-thunk";
import * as Goal_Reducer from "./Reducers/Global_Reducer";

const logger = createLogger(
collapsed: (getState, action, logEntry) => !logEntry.error,
predicate: (getState, action) => !action.type.includes("@@redux-form")
);

const client = new ApolloClient();

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

export const store = createStore(
combineReducers(
goals: Goal_Reducer.goalReducer,
apollo: client.reducer(),
form: formReducer
),
, //initial state
composeEnhancers(applyMiddleware(client.middleware(), thunk, logger))
);





why are you using redux-thunk at all in this particular case?
– azium
Sep 3 at 22:30





could you clean up the formatting please? just run your code through prettier.io (you should be doing that anyways)
– azium
Sep 3 at 22:32





re formatting: good suggestion re thunk: I'm calling multiple serial actions elsewhere
– Zach_is_my_name
Sep 3 at 22:37





To address your other question: that's just how the thunk middleware works. If you have a thunk action creator, it returns another a function that can dispatch and get current state. The reason it gets the ability to dispatch is because you're usually performing some asynchronous task and want to dispatch an action to tell Redux it's finished.
– Li357
Sep 3 at 22:38





"If you have a thunk action creator, it returns another a function that can dispatch and get current state." Right, which is why I don't understand why a simple call to an action creator that produces an action and does the dispatching would need a dispatch it's self. Simply expect function() => (dispatch) => return dispatch(obj)
– Zach_is_my_name
Sep 3 at 22:42





2 Answers
2



Oh, you're just asking why you have to do store.dispatch(setStepPositionIndex()); and still dispatch() inside your thunk. Because store.dispatch() is what makes the inner returned thunk function get called with the right arguments, and dispatch()ing inside the thunk is what propagates the action to the reducers. I can see how this would be strange to a newcomer, because dispatch() is doing two different things.


store.dispatch(setStepPositionIndex());


dispatch()


store.dispatch()


dispatch()


dispatch()



First you dispatch the thunk, and the thunk dispatches the action.



Original answer



When using redux-thunk, and having your action creator returning a function ( return (dispatch, getState) => { ), then you must manually call dispatch(). You can't simply return from the inner function. That's the point of redux-thunk, to control the dispatch(es) manually.


redux-thunk


return (dispatch, getState) => {


dispatch()


redux-thunk



If you don't want to do this, instead of using getState(), you could simply dispatch your action from your component with goals or currentGoalSteps passed in as an argument.


getState()


goals


currentGoalSteps





thunks don't have to be async. The docs show this github.com/reduxjs/redux-thunk . Search for "conditional dispatch"
– Andy Ray
Sep 3 at 22:42





calling getState() in the thunk is a fine use of a thunk
– Andy Ray
Sep 3 at 22:46





but you don't need redux-thunk to do this, you can use mapStateToProps of the connect function to get the state of the store inside the component
– Olivier Boissé
Sep 3 at 22:52


redux-thunk


mapStateToProps


connect





I know, that's in my answer.
– Andy Ray
Sep 3 at 22:55





because the first dispatch doesn't actually reach the store's reducers, it simply execute a function passing dispatch et getState parameters to be able to dispatch the real action later, you can see my answer where I show you the actual code of redux-thunk, it doesn't call next(action) when the action is a function, it simply executes the function
– Olivier Boissé
Sep 3 at 23:05



dispatch


dispatch


getState


dispatch


redux-thunk


next(action)



Because when using redux-thunk if the action creator returns a function instead of a plain object, the function is executed and its returned value is returned by the dispatch function. setStepPositionIndex() returns a function not a plain object, so the result of store.dispatch(setStepPositionIndex()) will be :


dispatch


setStepPositionIndex()


store.dispatch(setStepPositionIndex())



type: SET_STEP_POSITION_INDEX,
stepsArr: newSteps



Actually redux-thunk is just a middleware, its code is really simple


redux-thunk


const thunk = store => next => action =>
typeof action === 'function'
? action(store.dispatch, store.getState)
: next(action)



You can see that when you pass a function, the middleware will execute it (with dispatch and getState parameters) and returns the function's value.


dispatch


getState



redux-thunk is usefull for dispatching an action under some conditions or after a delay, in your case I don't think you really need redux-thunk as you are dispatching an action depending on the current state. You can use mapStateToProps of your connected component to retrieve the state of the store


redux-thunk


redux-thunk


dispatching


mapStateToProps


connected



Thanks for contributing an answer to Stack Overflow!



But avoid



To learn more, see our tips on writing great answers.



Some of your past answers have not been well-received, and you're in danger of being blocked from answering.



Please pay close attention to the following guidance:



But avoid



To learn more, see our tips on writing great answers.



Required, but never shown



Required, but never shown




By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

𛂒𛀶,𛀽𛀑𛂀𛃧𛂓𛀙𛃆𛃑𛃷𛂟𛁡𛀢𛀟𛁤𛂽𛁕𛁪𛂟𛂯,𛁞𛂧𛀴𛁄𛁠𛁼𛂿𛀤 𛂘,𛁺𛂾𛃭𛃭𛃵𛀺,𛂣𛃍𛂖𛃶 𛀸𛃀𛂖𛁶𛁏𛁚 𛂢𛂞 𛁰𛂆𛀔,𛁸𛀽𛁓𛃋𛂇𛃧𛀧𛃣𛂐𛃇,𛂂𛃻𛃲𛁬𛃞𛀧𛃃𛀅 𛂭𛁠𛁡𛃇𛀷𛃓𛁥,𛁙𛁘𛁞𛃸𛁸𛃣𛁜,𛂛,𛃿,𛁯𛂘𛂌𛃛𛁱𛃌𛂈𛂇 𛁊𛃲,𛀕𛃴𛀜 𛀶𛂆𛀶𛃟𛂉𛀣,𛂐𛁞𛁾 𛁷𛂑𛁳𛂯𛀬𛃅,𛃶𛁼

Edmonton

Crossroads (UK TV series)