30

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":"Sincere@april.biz"}}
·previous: {"user":{},"requesting":true,"err":null}
·current: {"user":{"id":1,"username":"Bret","email":"Sincere@april.biz"},"requesting":false,"err":null}
double-beep
  • 5,031
  • 17
  • 33
  • 41
FullStackForger
  • 1,060
  • 2
  • 12
  • 18

1 Answers1

50

The order of middlewares matters. Try making logger last

const store = createStore(reducer, applyMiddleware(thunk, logger))
Yury Tarabanko
  • 44,270
  • 9
  • 84
  • 98
  • 1
    Thank you! Perfect. Wouldn't come up with that on my own. Would you care to explain it why order matters please? – FullStackForger Sep 01 '16 at 13:10
  • 5
    "why order matters" imagine there is an array of middlewares `middlewares` and `dispatch` will pass every event to each middleware from left to right. So if you have middleware that transforms action somehow (like thunk does) you do want it to run before logger logs it to console. – Yury Tarabanko Sep 01 '16 at 13:13
  • Makes perfect sense. Thank you. I am referencing this answer int [github issue](https://github.com/gaearon/redux-thunk/issues/91) – FullStackForger Sep 01 '16 at 13:15