How to make multiple api calls in redux-thunk?

Viewed 431

Here is what I tried.

const redux = require('redux')
const thunkMiddleware = require('redux-thunk').default
const axios = require('axios')
const reduxLogger = require('redux-logger')


const createStore = redux.createStore
const applyMiddleware = redux.applyMiddleware
const combineReducers = redux.combineReducers


const userState = {
    loading: false,
    users: [],
    error: ''
}

const todoState = {
    loading: false,
    todos: [],
    error: ''
}



const FETCH_USERS_REQUEST = 'FETCH_USERS_REQUEST'
const FETCH_USERS_SUCCESS = 'FETCH_USERS_SUCCESS'
const FETCH_USERS_FAILURE = 'FETCH_USERS_FAILURE'

const FETCH_TODOS_REQUEST = 'FETCH_TODOS_REQUEST'
const FETCH_TODOS_SUCCESS = 'FETCH_TODOS_SUCCESS'
const FETCH_TODOS_FAILURE = 'FETCH_TODOS_FAILURE'

const fetchUserRequest = () => {
    return {
        type: FETCH_USERS_REQUEST
    }
}

const fetchUserSuccess = users => {
    return {
        type: FETCH_USERS_SUCCESS,
        payload: users
    }
}


const fetchUserFailure = error => {
    return {
        type: FETCH_USERS_FAILURE,
        payload: error
    }
} 

const fetchTodosRequest = () => {
    return {
        type: FETCH_TODOS_REQUEST
    }
}

const fetchTodosSuccess = users => {
    return {
        type: FETCH_TODOS_SUCCESS,
        payload: users
    }
}


const fetchTodosFailure = error => {
    return {
        type: FETCH_TODOS_FAILURE,
        payload: error
    }
}



const userReducer = (state = userState, action) => {
    switch(action.type){
        case FETCH_USERS_REQUEST:
            return {
                ...state,
                loading: true
            }
        case FETCH_USERS_SUCCESS:
            return {
                error: '',
                loading: false,
                users: action.payload
            }
        case FETCH_USERS_SUCCESS:
            return {
                users: [],
                loading: false,
                error: action.payload
            }
        default:
            return  
    }
}

const todosReducer = (state = todoState, action) => {
    switch(action.type){
        case FETCH_TODOS_REQUEST:
            return {
                ...state,
                loading: true
            }
        case FETCH_TODOS_SUCCESS:
            return {
                error: '',
                loading: false,
                todos: action.payload
            }
        case FETCH_TODOS_SUCCESS:
            return {
                todos: [],
                loading: false,
                error: action.payload
            }
        default:
            return  
    }
}

const fetchUsers = () => {
    return function (dispatch) {
        dispatch(fetchUserRequest())
        axios.get(`https://jsonplaceholder.typicode.com/users`)
            .then(resp => {
                let users = resp.data.map(user => user.name)
                dispatch(fetchUserSuccess(users))
            })
            .catch(err => {
                dispatch(fetchUserFailure(err.message))
            })
    }
}

const fetchTodos = () => {
    return function (dispatch) {
        dispatch(fetchTodosRequest())
        axios.get(`https://jsonplaceholder.typicode.com/todos`)
            .then(resp => {
                let todos = resp.data
                dispatch(fetchTodosSuccess(todos))
            })
            .catch(err => {
                dispatch(fetchTodosFailure(err.message))
            })
    }
}

const rootReducer = combineReducers({
    users: userReducer,
    todos: todosReducer
})

const store = createStore(rootReducer, applyMiddleware(thunkMiddleware))
console.log('initial state', store.getState()) 
store.subscribe(() => {console.log(store.getState())})
store.dispatch(fetchUsers())
store.dispatch(fetchTodos())



I am getting the following error. Error: The slice reducer for key "users" returned undefined during initialization. If the state passed to the reducer is undefined, you must explicitly return the initial state. The initial state may not be undefined. If you don't want to set a value for this reducer, you can use null instead of undefined.

1 Answers

You need to return existing return state in default case instead of return

todoReducer

const todosReducer = (state = todoState, action) => {
    switch(action.type){
        case FETCH_USERS_REQUEST:
            return {
                ...state,
                loading: true
            }
        case FETCH_USERS_SUCCESS:
            return {
                error: '',
                loading: false,
                users: action.payload
            }
        case FETCH_USERS_SUCCESS:
            return {
                users: [],
                loading: false,
                error: action.payload
            }
        default:
            return state;   // return state which has initial state values 
    }
}

userReducer

const userReducer = (state = userState, action) => {
    switch(action.type){
        case FETCH_USERS_REQUEST:
            return {
                ...state,
                loading: true
            }
        case FETCH_USERS_SUCCESS:
            return {
                error: '',
                loading: false,
                users: action.payload
            }
        case FETCH_USERS_SUCCESS:
            return {
                users: [],
                loading: false,
                error: action.payload
            }
        default:
            return state;   
    }
}
Related