React-Redux: Actions must be plain objects. Use custom middleware for async actions
When working with React-Redux, you might encounter the error message “Actions must be plain objects. Use custom middleware for async actions.” This error occurs when you try to dispatch an asynchronous action directly without using any middleware. In this blog post, we will explore the solutions to this problem and provide code snippets for each solution.
Solution 1: Using Redux Thunk Middleware
Redux Thunk is a popular middleware that allows you to write action creators that return functions instead of plain objects. These functions can perform asynchronous operations and dispatch multiple actions. To use Redux Thunk, you need to install it as a dependency:
npm install redux-thunk
Once installed, you can apply the middleware to your Redux store:
// store.js
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers';
const store = createStore(rootReducer, applyMiddleware(thunk));
export default store;
Now you can write asynchronous action creators using Redux Thunk. Here’s an example:
// actions.js
import axios from 'axios';
export const fetchData = () => {
return async (dispatch) => {
dispatch({ type: 'FETCH_DATA_REQUEST' });
try {
const response = await axios.get('/api/data');
dispatch({ type: 'FETCH_DATA_SUCCESS', payload: response.data });
} catch (error) {
dispatch({ type: 'FETCH_DATA_FAILURE', payload: error.message });
}
};
};
Solution 2: Using Redux Saga Middleware
Redux Saga is another middleware that allows you to handle side effects in a more declarative way using ES6 generators. To use Redux Saga, you need to install it as a dependency:
npm install redux-saga
Once installed, you can create a saga file to handle your asynchronous actions:
// saga.js
import { takeLatest, call, put } from 'redux-saga/effects';
import axios from 'axios';
function* fetchDataSaga() {
try {
const response = yield call(axios.get, '/api/data');
yield put({ type: 'FETCH_DATA_SUCCESS', payload: response.data });
} catch (error) {
yield put({ type: 'FETCH_DATA_FAILURE', payload: error.message });
}
}
export function* watchFetchData() {
yield takeLatest('FETCH_DATA_REQUEST', fetchDataSaga);
}
Then, in your store configuration, you can apply the saga middleware:
// store.js
import { createStore, applyMiddleware } from 'redux';
import createSagaMiddleware from 'redux-saga';
import rootReducer from './reducers';
import { watchFetchData } from './saga';
const sagaMiddleware = createSagaMiddleware();
const store = createStore(rootReducer, applyMiddleware(sagaMiddleware));
sagaMiddleware.run(watchFetchData);
export default store;
Now you can dispatch an action to trigger the saga:
// actions.js
export const fetchData = () => {
return { type: 'FETCH_DATA_REQUEST' };
};
Conclusion
By using custom middleware like Redux Thunk or Redux Saga, you can handle asynchronous actions in your React-Redux application without encountering the “Actions must be plain objects” error. Choose the middleware that best fits your project requirements and enjoy the benefits of writing clean and maintainable asynchronous code.
Leave a Reply