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))
);
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.
why are you using redux-thunk at all in this particular case?
– azium
Sep 3 at 22:30