英文:
"Actions must be plain objects. Use custom middleware for async actions." Even though thunk is applied
问题
I'll provide translations for the code snippets you provided:
applying thunk
import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import logger from 'redux-logger';
import { composeWithDevTools } from 'redux-devtools-extension';
import rootReducer from './services/reducers/root_reducer.js';
// Apply logger middleware only in the dev environment.
const composedEnhancer = compose(composeWithDevTools(), applyMiddleware(thunk, logger.default));
const configureStore = (preloadedState = {}) => {
return createStore(rootReducer, preloadedState, composedEnhancer);
};
export default configureStore;
index.js
import './assets/styles/reset.css';
import './assets/styles/index.css';
import React from 'react';
import ReactDOM from 'react-dom/client';
import { Provider } from 'react-redux';
import { BrowserRouter as Router } from 'react-router-dom';
import configureStore from './store.js';
import App from './app.js';
const rootElement = document.getElementById('root');
const root = ReactDOM.createRoot(rootElement);
root.render(
<Router>
<Provider store={configureStore()}>
<App />
</Provider>
</Router>
)
thunk action
import UserApi from '../api/user_api.js';
import { UserActions } from '../constants/actions.js';
import { displayError } from './error_actions.js';
import userPool from '../../user_pool.js';
export const addUser = (user) => {
return {
type: UserActions.addUser,
payload: user
};
};
export const register = (registerData) => {
return async (dispatch) => {
userPool.signUp(registerData.email, registerData.password, registerData.attributeList, null, (error, result) => {
if (error) {
return dispatch(displayError(error));
} else {
return dispatch(addUser(result.user));
}
});
}
}
dispatching thunk action
// Called when the form is submitted
const onSubmit = (event) => {
event.preventDefault();
const registerParams = {
email: user.email,
password: user.password,
attributeList: []
};
delete user.email;
delete user.password;
Object.entries(user).forEach(([key, value]) => {
if (key === "birthdate") {
const options = { year: 'numeric', month: '2-digit', day: '2-digit' };
value = value.toLocaleDateString('en-US', options).replace(/\//g, '-');
}
let attributeParams = {
Name: key,
Value: value
};
let cognitoAttribute = new CognitoUserAttribute(attributeParams);
registerParams.attributeList.push(cognitoAttribute);
});
dispatch(register(registerParams));
};
英文:
I am trying to figure out why I am getting "Actions must be plain objects. Use custom middleware for async actions." when I dispatch my thunk action. From my understanding, the normal cause of this issue would be that my thunk middleware wasn't applied, and thus redux only expects POJO actions, instead of thunk actions. However, unless I am mistaken, I believe I have already done that. I also double checked to make sure that my thunk action creator was, in fact, returning a thunk action. I have looked around, and even asked chatgpt, and I can't seem to find any solution to this issue. Here is the code:
applying thunk
import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import logger from 'redux-logger';
import { composeWithDevTools } from 'redux-devtools-extension';
import rootReducer from './services/reducers/root_reducer.js';
// apply logger middleware only in dev env
const composedEnhancer = compose(composeWithDevTools(), applyMiddleware(thunk, logger.default));
const configureStore = (preloadedState = {}) => {
return createStore(rootReducer, preloadedState, composedEnhancer);
};
export default configureStore;
index.js
import './assets/styles/reset.css';
import './assets/styles/index.css';
import React from 'react';
import ReactDOM from 'react-dom/client';
import { Provider } from 'react-redux';
import { BrowserRouter as Router } from 'react-router-dom';
import configureStore from './store.js';
import App from './app.js';
const rootElement = document.getElementById('root');
const root = ReactDOM.createRoot(rootElement);
root.render(
<Router>
<Provider store={configureStore()}>
<App />
</Provider>
</Router>
)
thunk action
import UserApi from '../api/user_api.js';
import { UserActions } from '../constants/actions.js';
import { displayError } from './error_actions.js';
import userPool from '../../user_pool.js';
export const addUser = (user) => {
return {
type: UserActions.addUser,
payload: user
};
};
export const register = (registerData) => {
return async (dispatch) => {
userPool.signUp(registerData.email, registerData.password, registerData.attributeList, null, (error, result) => {
if (error) {
return dispatch(displayError(error));
} else {
return dispatch(addUser(result.user));
}
});
}
}
dispatching thunk action
// Called when form is submitted
const onSubmit = (event) => {
event.preventDefault();
const registerParams = {
email: user.email,
password: user.password,
attributeList: []
};
delete user.email;
delete user.password;
Object.entries(user).forEach(([key, value]) => {
if (key === "birthdate") {
const options = { year: 'numeric', month: '2-digit', day: '2-digit' };
value = value.toLocaleDateString('en-US', options).replace(/\//g, '-');
}
let attributeParams = {
Name: key,
Value: value
};
let cognitoAttribute = new CognitoUserAttribute(attributeParams);
registerParams.attributeList.push(cognitoAttribute);
});
dispatch(register(registerParams));
};
答案1
得分: 2
One potential issue is that this line looks wrong:
const composedEnhancer = compose(composeWithDevTools(), applyMiddleware(thunk, logger.default));
There's three problems in that one line:
applyMiddleware
should always be first- if you're adding the devtools setup it should be last
- but actually
composeWithDevtools()
replaces the standalonecompose
so it really should be:
const composedEnhancer = composeWithDevtools(applyMiddleware(thunk, logger.default));
I'm not certain that is the cause of the error, but there's a good chance.
HOWEVER, there's another issue:
The style of Redux logic you're writing is very outdated.
Today, all Redux users should be using our official Redux Toolkit package to write their Redux code. It drastically simplifies Redux usage, and that includes some of the code in your example.
In particular, RTK's configureStore
API sets up the store with the thunk middleware and Redux DevTools already configured, and RTK's createAsyncThunk
will do the "dispatch actions for an async request" work for you.
See our docs for details on how to use Redux Toolkit:
英文:
One potential issue is that this line looks wrong:
const composedEnhancer = compose(composeWithDevTools(), applyMiddleware(thunk, logger.default));
There's three problems in that one line:
applyMiddleware
should always be first- if you're adding the devtools setup it should be last
- but actually
composeWithDevtools()
replaces the standalonecompose
so it really should be:
const composedEnhancer = composeWithDevtools(applyMiddleware(thunk, logger.default));
I'm not certain that is the cause of the error, but there's a good chance.
HOWEVER, there's another issue:
The style of Redux logic you're writing is very outdated.
Today, all Redux users should be using our official Redux Toolkit package to write their Redux code. It drastically simplifies Redux usage, and that includes some of the code in your example.
In particular, RTK's configureStore
API sets up the store with the thunk middleware and Redux DevTools already configured, and RTK's createAsyncThunk
will do the "dispatch actions for an async request" work for you.
See our docs for details on how to use Redux Toolkit:
答案2
得分: 1
以下是翻译好的部分:
“onSubmit”回调通过使用“register()”的返回值调用“dispatch()”。来自“register()”的返回值是一个Promise,而不是可序列化的对象。
“register()”通过“dispatch()”的返回值来履行(解析),后者也返回一个Promise。
英文:
...what @markerikson said plus...
The onSubmit
callback makes a call to dispatch()
with the return from register()
as its argument. The return from register()
is a Promise, not a serializable object.
register()
fulfills (resolves) with the return value from dispatch()
which returns a Promise.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论