当尝试将产品添加到用户收藏夹时,我收到此错误。尽管 redux 的状态正在正确更新。 我已经使用 Redux Thunk 进行身份验证,但我试图避免添加许多额外的减速器,因为只为一个函数添加大量代码;并开始使用productService.js文件。
userSlice.js
import {
createAction,
createSlice,
} from "@reduxjs/toolkit";
import {
loginUser,
registerUser,
} from "../actions/authActions";
import { getWithExpiry } from "../../utils/setStorage";
export const addFavoritesError = createAction(
"addFavoritesError"
);
const savedUserInfo = getWithExpiry("userInfo")
? getWithExpiry("userInfo")
: null;
const savedToken = getWithExpiry("userToken")
? getWithExpiry("userToken")
: null;
const initialValue = {
isLoading: false,
userInfo: savedUserInfo,
userToken: savedToken,
error: null,
success: false,
};
const authSlice = createSlice({
name: "auth",
initialState: initialValue,
reducers: {
login: (state) => {
loginUser().then((res) => {
// history.pushState('/');
});
},
logOut: (state) => {
return {
...state.initialState,
isLoading: false,
userInfo: null,
userToken: null,
error: null,
success: false,
};
},
signUp: (state) => {
registerUser().then((res) => {
// history.pushState('/');
});
},
addFavorites: (state, action) => {
return {
...state,
userInfo: {
...state.userInfo,
favorites: [...action.payload],
},
};
},
},
extraReducers: {
// 1 login user
[loginUser.pending]: (state) => {
state.isLoading = true;
state.error = null;
},
[loginUser.fulfilled]: (state, { payload }) => {
state.isLoading = false;
state.success = true;
state.userInfo = payload.data.user;
state.userToken = payload.token;
},
[loginUser.rejected]: (state, { payload }) => {
state.isLoading = false;
state.error = payload;
},
// 2 register user
[registerUser.pending]: (state) => {
state.isLoading = true;
state.error = null;
},
[registerUser.fulfilled]: (state, { payload }) => {
state.isLoading = false;
state.success = true;
state.userInfo = payload;
state.userToken = payload.token;
},
[registerUser.rejected]: (state, { payload }) => {
state.isLoading = false;
state.error = payload;
},
},
});
export const { logOut, addFavorites } = authSlice.actions;
export default authSlice.reducer
userService.js
import apiActions from "../../utils/api";
import { addFavorites, addFavoritesError } from "../slices/userSlice";
export const AddProdToFavorites = async (dispatch, user_id, prod_id) => {
try {
// api call
const data = await apiActions.addProdToUserFav(user_id, prod_id);
dispatch(addFavorites(data));
} catch {
dispatch(addFavoritesError());
}
};`
ProductCard.js
import React, { useCallback, useState } from "react";
import { useDispatch} from "react-redux";
import { AddProdToFavorites} from "../../../store/services/userService";
function DestinationsDisplayCard(props) {
const { userToken, name, price} = props;
const [favored, setFavored] = useState(false);
const dispatch = useDispatch();
const addItemtoFav = useCallback(() => {
setFavored((currrent) => !currrent);
dispatch(AddProdToFavorites(dispatch, userToken, prodId));
}, [favored]);
const removeItemFromFav = useCallback(() => {}, [favored]);
return (
<div className="productCard">
<p>{name}</p>
<p>${price}</p>
{userToken ? (
<button
onClick={favored ? removeItemFromFav : addItemtoFav}
>
</button>
) : null}
</div>
)
}
api.js
import axios from "axios";
const baseURL = "<<the url for api>>";
const apiActions = {
addProdToUserFav: async (user_id, prod_id) => {
const res = await axios.post(
`${baseURL}/v1/user/addFavorite`,
{
userId: user_id,
prodId: prod_id,
}
);
return res.data.data.user.favorites;
},
// this endpoint returns a list of object [{product2}{product2}] (with name, price, discount, etc)
}
我预计 state.userInfo.favorites 会更新,它确实如此,但我收到了此错误。
Uncaught Error: Actions must be plain objects. Use custom middleware for async actions.
VM41:1 Uncaught Error: Actions must be plain objects. Use custom middleware for async actions.
at Object.performAction (<anonymous>:1:41504)
at k (<anonymous>:3:1392)
at s (<anonymous>:3:5102)
at serializableStateInvariantMiddleware.ts:210:1
at index.js:20:1
at Object.dispatch (immutableStateInvariantMiddleware.ts:264:1)
at dispatch (<anonymous>:6:7391)
at DestinationsDisplay.card.jsx:23:1
at HTMLUnknownElement.callCallback (react-dom.development.js:4164:1)
at Object.invokeGuardedCallbackDev (react-dom.development.js:4213:1)
“未捕获的错误:操作必须是普通对象”是您看到的错误。 “使用自定义中间件进行异步操作”意味着您尝试在不使用 Redux Thunk 或 Redux Saga 等中间件的情况下分派异步操作。 Redux 中的异步操作需要中间件来处理。如果您还没有安装,请下载并安装 Redux Thunk:
npm install redux-thunk
Redux Thunk 现在应该包含在您的 Redux 存储配置中:
// store.js
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers'; // Replace with your actual reducer file
const store = createStore(rootReducer, applyMiddleware(thunk));
export default store;
修改您的
AddProdToFavorites
方法,使其返回一个异步执行操作的函数。调用 AddProdToFavorites
方法时,您必须另外提供 user_id
和 prod_id
作为参数:
// userService.js
import apiActions from "../../utils/api";
import { addFavorites, addFavoritesError } from "../slices/userSlice";
export const AddProdToFavorites = (user_id, prod_id) => async (dispatch) => {
try {
// api call
const data = await apiActions.addProdToUserFav(user_id, prod_id);
dispatch(addFavorites(data));
} catch {
dispatch(addFavoritesError());
}
};
修改您的组件以适当地调用
AddProdToFavorites
函数:
// ProductCard.js
import React, { useCallback, useState } from "react";
import { useDispatch, useSelector } from "react-redux"; // Import useSelector
import { AddProdToFavorites } from "../../../store/services/userService";
import { selectUserInfo } from "../../../store/slices/userSlice"; // Import selector
function DestinationsDisplayCard(props) {
const { userToken, name, price, prodId } = props;
const [favored, setFavored] = useState(false);
const dispatch = useDispatch();
const userInfo = useSelector(selectUserInfo); // Use useSelector to access user info
const addItemtoFav = useCallback(() => {
setFavored((current) => !current);
dispatch(AddProdToFavorites(userInfo.id, prodId)); // Pass user_id and prod_id
}, [favored, userInfo, prodId]);
const removeItemFromFav = useCallback(() => {}, [favored]);
return (
<div className="productCard">
<p>{name}</p>
<p>${price}</p>
{userToken ? (
<button onClick={favored ? removeItemFromFav : addItemtoFav}></button>
) : null}
</div>
);
}
export default DestinationsDisplayCard;
小心地将
selectUserInfo
替换为 Redux 存储中提取用户信息的实际选择器。