Search code examples
reduxreact-hooksredux-thunk

Difficulty implementing redux thunk


This is my first time working with redux hooks and I keep receiving the error: "Error: Actions must be plain objects. Use custom middleware for async actions."

I have added the middleware thunk. Following the other peoples questions, I am not sure where I am making the mistake. I'm looking for an explanation on what I am doing wrong and what I should be reading in order to fix it.

Actions:

export const fetchNewsData = () => {
    return (dispatch) => {
        axios.get('http://localhost:3001/getnews')
            .then(response => {
                console.log(response.data);
                
                const data = response.data;
                dispatch(loadNews(data));
            })
            .catch(error => {
                console.log(error);

                dispatch(errorOnNews(error));
            });
    }
}

export const loadNews = (fetchedData) => {
    return {
        type: LOAD_NEWS,
        payload: fetchedData
    }
}

export const errorOnNews = (errorMessage) => {
    return {
        type: ERROR_ON_NEWS,
        payload: errorMessage
    }
} 

Reducer:

const initialState = {
    fetched: false,
    data: [],
    input: '',
    filtered: [],
    error: ''
}

const newsReducer = (state = initialState, action) => {
    switch(action.type) {
        case LOAD_NEWS:
            return {
                ...state,
                fetched: true,
                data: action.payload
            }

        case FILTER_NEWS:
            return {
                ...state
            }

        case ERROR_ON_NEWS:
            return {
                ...state,
                error: action.payload
            }
        
        default: return state;
    }
}

Store:

import { createStore, applyMiddleware } from 'redux';
import ReduxThunk from 'redux-thunk';
import rootReducer from './rootReducer';
const store = createStore(rootReducer, applyMiddleware(thunk));

Component:

const fetch = useDispatch(fetchNewsData());

useEffect(() => {
        if(hasFetched){
            // work on true condition
        } else {
            fetch(); // fails on this line.
        }
    }, []);

Solution

  • useDispatch does not work like this, as it ignores all arguments and just returns you a dispatch function. So you have called dispatch() there, which essentially equals dispatch(undefined) - and the store doesn't know what to make of that action.

    Do this instead:

    const dispatch = useDispatch();
    
    useEffect(() => {
            if(hasFetched){
                // work on true condition
            } else {
                dispatch(fetchNewsData()); // fails on this line.
            }
        }, []);
    

    Also, generally you are writing a very outdated style of redux here that we do not really recommend to learn or use in new applications any more. You might have been following an outdated tutorial - as this style requires you to write multiple times the necessary code and is much more error prone.

    For up-to-date tutorials featuring modern redux with the official redux toolkit please see the official redux tutorials