在我的productSlice中,createProduct
将产品加载到数据库中,但通常保持在挂起状态。
与deleteProduct
类似,它删除,但仍处于挂起状态。getProduct
始终呈现以前产品的数据。
在我的商店里设置了logger middleWare后,我现在有了更多关于我的crud的信息- createProduct有时运行没有问题。product/create/fulfilled
,紧接着:
错误状态。product.push不是函数
所以它不会跳到下一个状态。
deleteProduct - action也会发生同样的情况:product/delete/fulfilled
,紧接着:
错误状态。product。filter不是函数
getProduct - prevState、action和next状态具有正确的数据,但文本值显然是在getProduct启动之前呈现的
还原切片:
import {createSlice, createAsyncThunk} from '@reduxjs/toolkit'
import { RootState } from '../../app/store'
import productsService from './productsService'
import {UpdateProductData} from '../../pages/ProductEdit'
export interface Product{
_id?:string,
id?:string,
image:string,
title:string,
producer:string,
categories:string[],
desc:string,
price:string,
currency:string,
colors:string[],
sizes:string[],
inStock:boolean,
createdAt:Date,
updatedAt?:Date,
accessToken?:string,
}
export interface InitialState{
product:Product[],
allProducts:Product[],
isLoading:boolean,
isSuccess:boolean,
isError:boolean,
message:string,
}
const initialState: InitialState ={
product:[],
allProducts:[],
isLoading:false,
isSuccess:false,
isError:false,
message:"",
}
type AsyncThunkConfig = {
state:RootState
}
export const createProduct = createAsyncThunk<Product, FormData, AsyncThunkConfig>('/product/create', async (productData, thunkAPI) => {
try{
const token:string = thunkAPI.getState().auth.user!.accessToken;
return await productsService.createProduct(productData, token);
} catch(error:any){
const message =
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString()
return thunkAPI.rejectWithValue(message as string)
}
})
export const updateProduct = createAsyncThunk<Product[], UpdateProductData, AsyncThunkConfig>('/product/update', async (updateProductData, thunkAPI)=>{
try{
const token:string = thunkAPI.getState().auth.user!.accessToken;
return await productsService.updateProduct(updateProductData, token);
} catch(error:any){
const message =
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString()
return thunkAPI.rejectWithValue(message as string)
}
})
export const deleteProduct = createAsyncThunk<Product, string, AsyncThunkConfig>('product/delete', async (Id, thunkAPI)=>{
try{
const token = thunkAPI.getState().auth.user!.accessToken;
return await productsService.deleteProduct(Id, token);
} catch(error:any){
const message =
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString()
return thunkAPI.rejectWithValue(message as string)
}
})
export const getProduct = createAsyncThunk<Product[], string, AsyncThunkConfig>('product/find', async (Id, thunkAPI)=>{
try{
return await productsService.getProduct(Id);
} catch(error:any){
const message =
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString()
return thunkAPI.rejectWithValue(message as string)
}
})
export const getAllProducts = createAsyncThunk<Product[], void, AsyncThunkConfig>('/product/findAll', async (_, thunkAPI)=>{
try{
return await productsService.getAllProducts();
} catch(error:any){
const message =
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString()
return thunkAPI.rejectWithValue(message as string)
}
})
export const productsSlice = createSlice({
name:"products",
initialState,
reducers:{
reset:(state)=>initialState,
},
extraReducers(builder) {
builder
.addCase(createProduct.pending, (state)=>{
state.isLoading = true;
})
.addCase(createProduct.fulfilled, (state, action)=>{
state.isLoading = false;
state.isSuccess = true;
state.product.push(action.payload);
})
.addCase(createProduct.rejected, (state,action:any)=>{
state.isLoading = false;
state.isError = true;
state.message = action.payload;
})
.addCase(updateProduct.pending, (state)=>{
state.isLoading = true;
})
.addCase(updateProduct.fulfilled, (state, action)=>{
state.isLoading = false;
state.isSuccess = true;
state.product = action.payload;
})
.addCase(updateProduct.rejected, (state, action:any)=>{
state.isLoading = false;
state.isError = true;
state.message = action.payload;
})
.addCase(deleteProduct.pending, (state)=>{
state.isLoading = true;
})
.addCase(deleteProduct.fulfilled, (state, action)=>{
state.isLoading = false;
state.isSuccess = true;
state.product = state.product.filter((item)=>item._id !== action.payload.id);
})
.addCase(deleteProduct.rejected, (state, action:any)=>{
state.isLoading = false;
state.isError = true;
state.message = action.payload;
})
.addCase(getProduct.pending, (state)=>{
state.isLoading = true;
})
.addCase(getProduct.fulfilled, (state, action)=>{
state.isLoading = false;
state.isSuccess = true;
state.product = action.payload;
})
.addCase(getProduct.rejected, (state, action:any)=>{
state.isLoading = false;
state.isError = true;
state.message = action.payload;
})
.addCase(getAllProducts.pending, (state)=>{
state.isLoading = true;
})
.addCase(getAllProducts.fulfilled, (state, action)=>{
state.isLoading = false;
state.isSuccess = true;
state.allProducts = action.payload;
})
.addCase(getAllProducts.rejected, (state, action:any)=>{
state.isLoading = false;
state.isError = true;
state.message = action.payload;
})
}
})
export const {reset} = productsSlice.actions;
export default productsSlice.reducer;
还原服务:
import axios from 'axios';
import { UpdateProductData } from '../../pages/ProductEdit';
const API_URL = 'http://localhost:5001/api/products/';
const createProduct = async (productData:FormData, token:string)=>{
const config = {
headers:{
'Content-Type':"multipart/form-data",
token: `Bearer ${token}`,
}
}
const response = await axios.post(API_URL, productData, config);
console.log(response.data);//immediatly correct data
return response.data;
}
const updateProduct = async (updateProductData:UpdateProductData, token:string)=>{
const config ={
headers:{
'Content-Type':"multipart/form-data",
token:`Bearer ${token}`
}
}
const response = await axios.put(API_URL+updateProductData.id, updateProductData.productData, config);
console.log(response.data);
return response.data;
}
const deleteProduct = async (id:string, token:string)=>{
const config = {
headers:{
token:`Bearer ${token}`
}
}
const response = await axios.delete(API_URL + id, config);
console.log(response.data);
return response.data;
}
const getProduct = async (id:string)=>{
const getUrl = `find/${id}`;
const response = await axios.get(API_URL+getUrl);
console.log(response.data)
return response.data;
}
const getAllProducts = async ()=>{
const response = await axios.get(API_URL+ 'find');
console.log(response.data);
return response.data;
}
const productsService = {
createProduct,
updateProduct,
deleteProduct,
getProduct,
getAllProducts
}
export default productsService
储存:
import { configureStore, ThunkAction, Action} from '@reduxjs/toolkit';
import authReducer from '../features/authSlice';
import userReducer from '../features/user/userSlice'
import productReducer from '../features/products/productsSlice';
import descriptionItemReducer from '../features/descriptionItems/descriptionItemSlice';
import sliderItemsReducer from '../features/sliderItems/sliderItemSlice';
import storage from 'redux-persist/lib/storage'
import {persistReducer} from 'redux-persist'
const persistConfig = {
key: 'root',
version: 1,
storage,
}
const persistedUserReducer = persistReducer(persistConfig,userReducer)
const persistedProductReducer = persistReducer(persistConfig, productReducer)
const persistedSliderReducer = persistReducer(persistConfig, sliderItemsReducer)
export const store = configureStore({
reducer: {
auth:authReducer,
user:persistedUserReducer,
products:persistedProductReducer,
descriptionItem:descriptionItemReducer,
sliderItems:persistedSliderReducer,
},
});
export type AppDispatch = typeof store.dispatch;
export type RootState = ReturnType<typeof store.getState>;
export type AppThunk<ReturnType = void> = ThunkAction<
ReturnType,
RootState,
unknown,
Action<string>
>;
我从后端添加代码:
import {Router, Request, Response} from 'express';
const productsRouter = Router();
import {verifyTokenAndAdmin} from '../middleware/jwtVerify';
import Products from '../models/products';
import upload from '../utils/multer';
const cloudinary = require('../utils/cloudinary');
import path from 'path'
productsRouter.post('/', upload.single('image'), verifyTokenAndAdmin, async (req:Request, res:Response)=>{
console.log(req.file);
console.log(req.body);
let fileUrl = req.file!.path.replace(/\\/g, "/");
console.log(fileUrl);
try{
const uploadResult = await cloudinary.uploader.upload(fileUrl, {
upload_preset: "webshop_ts_mern",
resource_type: "auto",
})
const newProducts = new Products({
cloudinary_id: uploadResult.public_id,
title: req.body.title,
producer: req.body.producer,
categories: JSON.parse(req.body.categories).split(' '),
desc: req.body.desc,
price: req.body.price,
currency:req.body.currency,
colors:JSON.parse(req.body.colors).split(' '),
sizes: JSON.parse(req.body.sizes).split(' '),
inStock: req.body.inStock,
image: uploadResult.secure_url,
})
console.log(newProducts);
const savedproducts = await newProducts.save();
res.status(200).json(savedproducts);
} catch(error){
res.status(403)
console.log(error);
throw new Error("Action failed");
}
});
//update
productsRouter.put('/:id',upload.single("image"), verifyTokenAndAdmin, async (req:Request, res:Response)=>{
console.log(req.file);
console.log(req.body)
try{
let updatedProducts = await Products.findById(req.params.id);
if(req.file){
await cloudinary.uploader.destroy(updatedProducts?.cloudinary_id);
}
let result;
if(req.file){
let fileUrl = req.file!.path.replace(/\\/g, "/");
result = await cloudinary.uploader.upload(fileUrl, {
upload_preset: "webshop_ts_mern",
resource_type: "auto",
})
}
const updatedData = {
title: req.body.title || updatedProducts!.title,
producer: req.body.producer || updatedProducts!.producer,
categories: JSON.parse(req.body.categories) || updatedProducts!.categories,
desc: req.body.desc || updatedProducts!.desc,
price: req.body.price || updatedProducts!.price,
currency: req.body.currency || updatedProducts!.currency,
colors: JSON.parse(req.body.colors) || updatedProducts!.colors,
sizes: JSON.parse(req.body.sizes) || updatedProducts!.sizes,
inStock: req.body.inStock || updatedProducts!.inStock,
cloudinary_id: result ? result.public_id : updatedProducts!.cloudinary_id,
image: result ? result.secure_url : updatedProducts!.image,
}
console.log(updatedData);
updatedProducts = await Products.findByIdAndUpdate(req.params.id, updatedData, {
new:true,
})
res.status(200).json(updatedProducts);
} catch(error){
res.status(404)
console.log(error);
throw new Error('Not found')
}
});
//delete
productsRouter.delete('/:id', verifyTokenAndAdmin, async (req:Request, res:Response)=>{
try{
let deleteProducts = await Products.findById(req.params.id);
await cloudinary.uploader.destroy(deleteProducts!.cloudinary_id);
await deleteProducts!.remove();
res.status(200).json("Produkt wurde gelöscht");
} catch(error){
res.status(404)
throw new Error("Nicht gefunden")
}
});
//get
productsRouter.get('/find/:id', async (req:Request, res:Response)=>{
try{
const products = await Products.findById(req.params.id);
res.status(200).json(products)
} catch(error){
res.status(404)
throw new Error("Nicht gefunden");
}
});
//get All
productsRouter.get('/find/', async (req:Request, res:Response)=>{
try{
const allProducts = await Products.find()
res.status(200).json(allProducts);
} catch(error){
res.status(404)
throw new Error("Not found");
}
})
export default productsRouter;
1条答案
按热度按时间aurhwmvo1#
在你的更新和删除控制器,你写的可选运算符不正确,你写了
!.
,而不是它应该是?.
。我已经为你更新了代码。