Here is the code I'm playing with
import { createStore, applyMiddleware } from 'redux' import thunk from 'redux-thunk' import axios from 'axios' const initialState = { user: {}, requesting: false, err: null } const reducer = (state = initialState, action) => { switch (action.type) { case 'REQ_USER_INIT': return { ...state, requesting: true } case 'REQ_USER_DATA': return { ...state, requesting: false, user: action.user } case 'REQ_USER_ERR': return { ...state, requesting: false, err: action.err } } return state; } const logger = (store) => (next) => (action) => { let previous = JSON.stringify(store.getState()) next(action) console.log( 'action: ' + JSON.stringify(action) + '\n\tprevious: ' + previous + '\n\tcurrent: ' + JSON.stringify(store.getState()) ) } const store = createStore(reducer, applyMiddleware(logger, thunk)) store.dispatch((dispatch) => { dispatch({ type: 'REQ_USER_INIT' }) // Fake Online REST API for Testing and Prototyping // break url to get an error response let usersEndpoint = 'https://jsonplaceholder.typicode.com/users/1' axios.get(usersEndpoint) .then((response) => { dispatch({ type: 'REQ_USER_DATA', user: { id: response.data.id, username: response.data.username, email: response.data.email, } }) }) .catch((error) => { dispatch({ type: 'REQ_USER_ERR', err: error.message }) }) })
I believe it is pretty straightforward, right? I dispatch REQ_USER_INIT
and then REQ_USER_DATA
once the response is received. I should log two actions, however I get 3. Second action is undefined
and I am strugling to figure out what causes it. Is it a bug with redux-thunk or am I doing something wrong?
Here is the output from my console:
action: {"type":"REQ_USER_INIT"} ·previous: {"user":{},"requesting":false,"err":null} ·current: {"user":{},"requesting":true,"err":null} action: undefined ·previous: {"user":{},"requesting":false,"err":null} ·current: {"user":{},"requesting":true,"err":null} action: {"type":"REQ_USER_DATA","user":{"id":1,"username":"Bret","email":"[email protected]"}} ·previous: {"user":{},"requesting":true,"err":null} ·current: {"user":{"id":1,"username":"Bret","email":"[email protected]"},"requesting":false,"err":null}
Where does this new dispatch argument come from? The short answer is that the redux-thunk middleware has access to the store, and can therefore pass in the store's dispatch and getState when invoking the thunk. The middleware itself is responsible for injecting those dependencies into the thunk.
Redux Thunk is a middleware that lets you call action creators that return a function instead of an action object. That function receives the store's dispatch method, which is then used to dispatch regular synchronous actions inside the function's body once the asynchronous operations have been completed.
A Redux app really only has one reducer function: the "root reducer" function that you will pass to createStore later on. That one root reducer function is responsible for handling all of the actions that are dispatched, and calculating what the entire new state result should be every time.
There is an issue with how fetchComments method is called inside the <Dashboard> component. Once a React component is connected to a Redux store, the data from the store ( mapStateToProps ) and the functions it can use to dispatch actions to the store ( mapDispatchToProps ) are passed to that component as an object.
The order of middlewares matters. Try making logger
last
const store = createStore(reducer, applyMiddleware(thunk, logger))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With