redux-toolkit中的数据流问题,react

vybvopom  于 2023-01-13  发布在  React
关注(0)|答案(1)|浏览(147)

在我的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;
aurhwmvo

aurhwmvo1#

在你的更新和删除控制器,你写的可选运算符不正确,你写了!.,而不是它应该是?.。我已经为你更新了代码。

//update
productsRouter.put('/:id',upload.single("image"), verifyTokenAndAdmin, async (req:Request, res:Response)=>{
  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")
  }
});

相关问题