Search code examples
reactjsreduxpromisereact-reduxredux-thunk

Reducer returned undefined (Redux-Thunk and Promise)


I already searched the web for hours for a solution for this problem. I found some hints and solutions for related problems, but not this problem. Maybe my store is configured the wrong way or i defined my reducer actions incorrect.

My problem is, that my reducer returns undefined on sending a post request to an API.

And here are the files. If a file is missing, please give me a feedback, and i'll instantly update the post.

I can fetch an entry with fetchEntry without problems, i can delete an entry with deleteEntry, the post request for updating an entry will be send successfully to the API and the entry gets updated, but the reducer somehow will not be informed about this successful action and returns undefined...

// redux/actions/entry.js
import axios from 'axios';

export const FETCH_ENTRY = 'fetch_entry';
export const CREATE_ENTRY = 'create_entry';
export const UPDATE_ENTRY = 'update_entry';
export const DELETE_ENTRY = 'delete_entry';
export const ERROR_ENTRY = 'error_entry';

const ROOT_URL  = 'http://localhost:8080/api';

// **This is the important part here**
export function updateEntry(type, data, callback) {
    return async (dispatch) => {        
        try {
            const request = axios.post(
                `${ROOT_URL}/${type}/edit/${data.id}`,
                data.formData
            ).then(() => callback());

            dispatch({ type: UPDATE_ENTRY, payload: request });
        } catch(error) {
            console.log(error);
        }
    }
}

// Not defined, tbd
export function createEntry(type, data, history) {
    
}

// **Everything else is working fine**
export function fetchEntry(type, id, history) {
    return async (dispatch) => {
        try {
            const request = await 
            axios.get(`${ROOT_URL}/${type}/get/${id}`);
            dispatch({ type: FETCH_ENTRY, payload: request });
        } catch(error) {
            history.push('/');
        }
    };
}

export function deleteEntry(type, id, callback) {
    return async (dispatch) => {
        try {
            const request = 
                axios.delete(`${ROOT_URL}/${type}/delete/${id}`)
                .then(() => callback());
            dispatch({ type: DELETE_ENTRY, payload: request });
        } catch(error) {
            console.log(error);
        }
    }
} 

My reducer is defined as followed:

 

// redux/recuders/reducer_entry.js 
import { CREATE_ENTRY, FETCH_ENTRY, DELETE_ENTRY, UPDATE_ENTRY } from 
'../actions/entry';

export default function(state = {}, action) {
    switch (action.type) {
    case CREATE_ENTRY:
        return action.payload.data;
    case DELETE_ENTRY:
        return action.type;
    case FETCH_ENTRY:
        return action.payload.data;
    case UPDATE_ENTRY:
        console.log(action);
        return action.payload.data;
    default:
        return state;
    }
}

The "calling" point which send the trigger to send the post request:

// EditEntry.js
  
this.props.updateEntry('type', data, () => {
            console.log("Successfully saved!");
            console.log(this.props);
});

My store is defined like this ...

// store.js
import { compose, createStore, applyMiddleware } from 'redux';
import { createBrowserHistory } from 'history';
import { syncHistoryWithStore } from 'react-router-redux';
import { createLogger } from 'redux-logger';
import thunk from 'redux-thunk';

import rootReducer from './redux/reducers';

const middleware = [
    createLogger(),
    thunk
];

const enhancers = compose(
    applyMiddleware(...middleware),
    window.devToolsExtension ? window.devToolsExtension() : f => f
)

// Create store
const store = createStore(
    rootReducer,
    {},
    enhancers
);

export const history = syncHistoryWithStore(createBrowserHistory(), 
store);

const createStoreWithMiddleware = applyMiddleware(thunk)(createStore);


export { createStoreWithMiddleware };

and given to the App like this..

// index.js

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import Routes from './Routes';
import registerServiceWorker from './registerServiceWorker';

import reducers from './redux/reducers';

import { createStoreWithMiddleware } from './store';

const store = createStoreWithMiddleware(reducers);

ReactDOM.render(
    <Provider store={store}>
        <Routes />
    </Provider>, 
    document.getElementById('root')
);
registerServiceWorker();

Last, the reducers/index.js (where combineReducers is called):

// redux/reducers/index.js

import { combineReducers } from 'redux';
import { routerReducer } from 'react-router-redux';
import EntryReducer from './reducer_entry';
import { reducer as FormReducer } from 'redux-form';

const rootReducer = combineReducers({
    routing: routerReducer,
    entry: EntryReducer,
    form: FormReducer
});

export default rootReducer;

Maybe someone of you can help with this?


Solution

  • You are not returning anything here from then block

    // **This is the important part here**
    export function updateEntry(type, data, callback) {
        return async (dispatch) => {        
            try {
                const request = axios.post(
                    `${ROOT_URL}/${type}/edit/${data.id}`,
                    data.formData
                ).then(() => callback());
    
                dispatch({ type: UPDATE_ENTRY, payload: request });
            } catch(error) {
                console.log(error);
            }
        }
    }