Can't fix error: Actions must be plain objects. Instead, the actual type was: 'function'
Can't fix error: Actions must be plain objects. Instead, the actual type was: 'function'
几天来我一直在尝试解决这个问题,在 SO 上阅读了类似的问题,但仍然找不到问题所在。
对于特定操作,我收到以下错误:Actions must be plain objects. Instead, the actual type was: 'function'
但问题是:它适用于某些功能但不适用于其他功能。
为了简洁省略了一些代码。
工作示例(onGetConnectors()
)
在这里,调用 actions.onGetConnectors()
工作正常,我收到来自状态更新的 connectors
。
CardDetail/index.js
const BoardDetailView = (props) => {
const {boardDetail, connectors, actions} = props;
const getBoardData = useCallback(() => {
if (boardDetail) {
console.log('[BoardDetailView] Board detail:', boardDetail);
actions.onGetConnectors(); // This works fine
return {
...boardDetail,
lanes: boardDetail.lanes || [], // if empty, add at least one lane
};
}
}, [boardDetail]);
const [boardData, setBoardData] = useState(getBoardData());
return (
<AppsContent
<Board
data={boardData}
onDataChange={shouldReceiveNewData}
components={{
BoardWrapper: BoardWrapper,
Card: CardDetail,
LaneHeader: ListHeader,
AddCardLink: AddCardButton,
NewCardForm: CardDrawer,
NewLaneForm: AddNewList,
NewLaneSection: NewListButton,
}}
/>
<CardDrawer open={addCardOpen} onCloseCard={onCloseCard} selectedLane={selectedLane} board={boardDetail} selectedCard={selectedCard} setSelectedCard={setSelectedCard} connectors={connectors} />
</AppsContent>
);
};
BoardDetailView.propTypes = {
boardDetail: PropTypes.object,
connectors: PropTypes.array,
actions: PropTypes.object,
};
function mapStateToProps(state) {
return {
connectors: state.connectors.connectors,
};
}
function mapDispatchToProps(dispatch) {
return {
actions: {
onGetConnectors: bindActionCreators(appGlobalActions.onGetConnectors, dispatch),
},
};
}
export default connect(mapStateToProps, mapDispatchToProps)(BoardDetailView);
redux/actios/Connectors.js
export const onGetConnectors = () => {
const {messages} = appIntl();
// ERROR DOES NOT OCCUR FOR THIS FUNCTION
return (dispatch) => {
dispatch({type: FETCH_START});
jwtAxios
.get('/connectors/')
.then((data) => {
if (data.status === 200) {
dispatch({type: FETCH_SUCCESS});
dispatch({type: GET_CONNECTORS, payload: data.data});
} else {
dispatch({
type: FETCH_ERROR,
payload: messages['message.somethingWentWrong'],
});
}
})
.catch((error) => {
dispatch({type: FETCH_ERROR, payload: error.message});
});
};
};
export const onGetAccounts = (accessId) => {
const {messages} = appIntl();
// ERROR OCCURS HERE <------------------
return (dispatch) => {
dispatch({type: FETCH_START});
jwtAxios
.get(`/accounts/?accessId=${accessId}`)
.then((data) => {
if (data.status === 200) {
console.log('data:', data);
dispatch({type: FETCH_SUCCESS});
dispatch({type: GET_ACCOUNTS, payload: data.data});
dispatch({
type: SHOW_MESSAGE,
payload: messages['message.accountsRetrieved'],
});
} else {
dispatch({
type: FETCH_ERROR,
payload: messages['message.somethingWentWrong'],
});
}
})
.catch((error) => {
dispatch({type: FETCH_ERROR, payload: error.message});
});
};
};
在下一个例子中使用了getAccounts()
,它抛出以下错误:
Uncaught Error: Actions must be plain objects. Instead, the actual type was: 'function'. You may need to add middleware to your store setup to handle dispatching other values, such as 'redux-thunk' to handle dispatching functions
.
这是我的 redux 商店,显示我已经在使用 redux-thunk
。
import {applyMiddleware, compose, createStore} from 'redux';
import reducers from '../reducers';
import {routerMiddleware} from 'connected-react-router';
import thunk from 'redux-thunk';
const createBrowserHistory = require('history').createBrowserHistory;
const history = createBrowserHistory();
const routeMiddleware = routerMiddleware(history);
const middlewares = [thunk, routeMiddleware];
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
export default function configureStore(initialState) {
const store = createStore(reducers(history), initialState, composeEnhancers(applyMiddleware(...middlewares)));
if (module.hot) {
// Enable Webpack hot module replacement for reducers
module.hot.accept('../reducers/index', () => {
const nextRootReducer = require('../reducers');
store.replaceReducer(nextRootReducer);
});
}
return store;
}
export {history};
失败示例 (onGetAccounts()
)
此处,从 useEffect
或 onRefreshButtonClick()
函数调用 onGetAccounts()
时会抛出错误。
const CardDetail = (props) => {
const {title, access, attachments, label, refreshedAccounts, date, comments, onClick, editable, actions} = props;
useEffect(() => {
if (access) {
console.log('[CardDetail] Getting accounts for access id:', access.id);
actions.onGetAccounts(access.id);
}
}, [access]);
const renderAccountData = (account) => {
let displayData = {
uniqueKey: '',
label: '',
value: '',
};
switch (account.vendorId) {
case 'bank':
displayData.uniqueKey = account.vendorAccountId;
displayData.label = account.asset;
displayData.value = `${account.balance}`;
break;
}
}
return (
<Box key={displayData.uniqueKey}>
<Box component='div'>
{displayData.label}
</Box>
<Box component='div'>
{displayData.value}
</Box>
</Box>
);
};
const onRefreshButtonClick = async (e) => {
e.stopPropagation();
console.log('[CardDetail] Refreshing accounts for access:', access);
actions.onGetAccounts(access.id);
};
return (
<Card
<Box
onClick={(e) => {
e.stopPropagation();
onClick(e);
}}>
{/* Accounts */}
<Box>
{refreshedAccounts?.map((account) => {
renderAccountData(account);
})}
</Box>
</Box>
</Card>
);
};
CardDetail.defaultProps = {
attachments: [],
accounts: [],
config: {},
label: [],
};
CardDetail.propTypes = {
title: PropTypes.string,
attachments: PropTypes.array,
label: PropTypes.array,
refreshedAccounts: PropTypes.array,
access: PropTypes.object,
date: PropTypes.string,
comments: PropTypes.array,
onClick: PropTypes.func,
editable: PropTypes.bool,
actions: PropTypes.object,
};
function mapStateToProps(state) {
return {
refreshedAccounts: state.connectors?.accounts,
};
}
function mapDispatchToProps(dispatch) {
return {
actions: {
onGetAccounts: bindActionCreators(appGlobalActions.onGetAccounts, dispatch),
},
};
}
export default connect(mapStateToProps, mapDispatchToProps)(CardDetail);
如果能帮助解决问题,我们将不胜感激。我不知所措地试图理解为什么 onGetConnectors()
有效但 onGetAccounts()
.
原来问题出在我共享的代码之外。
这是由于 react-trello
在 Card
组件中调用 API 时导致此问题。
几天来我一直在尝试解决这个问题,在 SO 上阅读了类似的问题,但仍然找不到问题所在。
对于特定操作,我收到以下错误:Actions must be plain objects. Instead, the actual type was: 'function'
但问题是:它适用于某些功能但不适用于其他功能。
为了简洁省略了一些代码。
工作示例(onGetConnectors()
)
在这里,调用 actions.onGetConnectors()
工作正常,我收到来自状态更新的 connectors
。
CardDetail/index.js
const BoardDetailView = (props) => {
const {boardDetail, connectors, actions} = props;
const getBoardData = useCallback(() => {
if (boardDetail) {
console.log('[BoardDetailView] Board detail:', boardDetail);
actions.onGetConnectors(); // This works fine
return {
...boardDetail,
lanes: boardDetail.lanes || [], // if empty, add at least one lane
};
}
}, [boardDetail]);
const [boardData, setBoardData] = useState(getBoardData());
return (
<AppsContent
<Board
data={boardData}
onDataChange={shouldReceiveNewData}
components={{
BoardWrapper: BoardWrapper,
Card: CardDetail,
LaneHeader: ListHeader,
AddCardLink: AddCardButton,
NewCardForm: CardDrawer,
NewLaneForm: AddNewList,
NewLaneSection: NewListButton,
}}
/>
<CardDrawer open={addCardOpen} onCloseCard={onCloseCard} selectedLane={selectedLane} board={boardDetail} selectedCard={selectedCard} setSelectedCard={setSelectedCard} connectors={connectors} />
</AppsContent>
);
};
BoardDetailView.propTypes = {
boardDetail: PropTypes.object,
connectors: PropTypes.array,
actions: PropTypes.object,
};
function mapStateToProps(state) {
return {
connectors: state.connectors.connectors,
};
}
function mapDispatchToProps(dispatch) {
return {
actions: {
onGetConnectors: bindActionCreators(appGlobalActions.onGetConnectors, dispatch),
},
};
}
export default connect(mapStateToProps, mapDispatchToProps)(BoardDetailView);
redux/actios/Connectors.js
export const onGetConnectors = () => {
const {messages} = appIntl();
// ERROR DOES NOT OCCUR FOR THIS FUNCTION
return (dispatch) => {
dispatch({type: FETCH_START});
jwtAxios
.get('/connectors/')
.then((data) => {
if (data.status === 200) {
dispatch({type: FETCH_SUCCESS});
dispatch({type: GET_CONNECTORS, payload: data.data});
} else {
dispatch({
type: FETCH_ERROR,
payload: messages['message.somethingWentWrong'],
});
}
})
.catch((error) => {
dispatch({type: FETCH_ERROR, payload: error.message});
});
};
};
export const onGetAccounts = (accessId) => {
const {messages} = appIntl();
// ERROR OCCURS HERE <------------------
return (dispatch) => {
dispatch({type: FETCH_START});
jwtAxios
.get(`/accounts/?accessId=${accessId}`)
.then((data) => {
if (data.status === 200) {
console.log('data:', data);
dispatch({type: FETCH_SUCCESS});
dispatch({type: GET_ACCOUNTS, payload: data.data});
dispatch({
type: SHOW_MESSAGE,
payload: messages['message.accountsRetrieved'],
});
} else {
dispatch({
type: FETCH_ERROR,
payload: messages['message.somethingWentWrong'],
});
}
})
.catch((error) => {
dispatch({type: FETCH_ERROR, payload: error.message});
});
};
};
在下一个例子中使用了getAccounts()
,它抛出以下错误:
Uncaught Error: Actions must be plain objects. Instead, the actual type was: 'function'. You may need to add middleware to your store setup to handle dispatching other values, such as 'redux-thunk' to handle dispatching functions
.
这是我的 redux 商店,显示我已经在使用 redux-thunk
。
import {applyMiddleware, compose, createStore} from 'redux';
import reducers from '../reducers';
import {routerMiddleware} from 'connected-react-router';
import thunk from 'redux-thunk';
const createBrowserHistory = require('history').createBrowserHistory;
const history = createBrowserHistory();
const routeMiddleware = routerMiddleware(history);
const middlewares = [thunk, routeMiddleware];
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
export default function configureStore(initialState) {
const store = createStore(reducers(history), initialState, composeEnhancers(applyMiddleware(...middlewares)));
if (module.hot) {
// Enable Webpack hot module replacement for reducers
module.hot.accept('../reducers/index', () => {
const nextRootReducer = require('../reducers');
store.replaceReducer(nextRootReducer);
});
}
return store;
}
export {history};
失败示例 (onGetAccounts()
)
此处,从 useEffect
或 onRefreshButtonClick()
函数调用 onGetAccounts()
时会抛出错误。
const CardDetail = (props) => {
const {title, access, attachments, label, refreshedAccounts, date, comments, onClick, editable, actions} = props;
useEffect(() => {
if (access) {
console.log('[CardDetail] Getting accounts for access id:', access.id);
actions.onGetAccounts(access.id);
}
}, [access]);
const renderAccountData = (account) => {
let displayData = {
uniqueKey: '',
label: '',
value: '',
};
switch (account.vendorId) {
case 'bank':
displayData.uniqueKey = account.vendorAccountId;
displayData.label = account.asset;
displayData.value = `${account.balance}`;
break;
}
}
return (
<Box key={displayData.uniqueKey}>
<Box component='div'>
{displayData.label}
</Box>
<Box component='div'>
{displayData.value}
</Box>
</Box>
);
};
const onRefreshButtonClick = async (e) => {
e.stopPropagation();
console.log('[CardDetail] Refreshing accounts for access:', access);
actions.onGetAccounts(access.id);
};
return (
<Card
<Box
onClick={(e) => {
e.stopPropagation();
onClick(e);
}}>
{/* Accounts */}
<Box>
{refreshedAccounts?.map((account) => {
renderAccountData(account);
})}
</Box>
</Box>
</Card>
);
};
CardDetail.defaultProps = {
attachments: [],
accounts: [],
config: {},
label: [],
};
CardDetail.propTypes = {
title: PropTypes.string,
attachments: PropTypes.array,
label: PropTypes.array,
refreshedAccounts: PropTypes.array,
access: PropTypes.object,
date: PropTypes.string,
comments: PropTypes.array,
onClick: PropTypes.func,
editable: PropTypes.bool,
actions: PropTypes.object,
};
function mapStateToProps(state) {
return {
refreshedAccounts: state.connectors?.accounts,
};
}
function mapDispatchToProps(dispatch) {
return {
actions: {
onGetAccounts: bindActionCreators(appGlobalActions.onGetAccounts, dispatch),
},
};
}
export default connect(mapStateToProps, mapDispatchToProps)(CardDetail);
如果能帮助解决问题,我们将不胜感激。我不知所措地试图理解为什么 onGetConnectors()
有效但 onGetAccounts()
.
原来问题出在我共享的代码之外。
这是由于 react-trello
在 Card
组件中调用 API 时导致此问题。