有没有办法可以在 React-router-dom V6 的前端渲染商店产品?

问题描述 投票:0回答:1

我正在构建一个电子商务网络应用程序,其中只有商店才能创建产品。每个产品都属于一个商店,每个商店都有自己的产品。因此,当我点击一家商店时,它会将我带到一个包含专门针对该商店的产品的页面。经过我所做的一切,我得到了一个空白页面,其中包含未定义的内部服务器错误。

这是我的商店controller.js

const Product = require("../models/product");

const ErrorHandler = require("../utils/errorHandler");
const catchAsyncErrors = require("../middlewares/catchAsyncErrors");
const APIFeatures = require("../utils/apiFeatures");
const cloudinary = require('cloudinary')

const crypto = require("crypto");
const geoCoder = require("../utils/geocoder");


exports.getProductsByShopId = catchAsyncErrors(async (req, res, next) => {
 const products = await Product.find({ shop: req.params.shopId });

 res.status(200).json({
   success: true,
   count: products.length,
   products,
 });
});

这是我的产品型号

   const slugify = require('slugify');

const productSchema = new mongoose.Schema({
 name: {
   type: String,
   required: [true, "Please enter product name"],
   trim: true,
   maxLength: [100, "Product name cannot exceed 100 characters"],
 },

 price: {
   type: Number,
   required: [true, "Please enter product price"],
   maxLength: [20, "Product name cannot exceed 20 characters"],
   default: 0.0,
 },
 description: {
   type: String,
   required: [true, "Please enter product description"],
 },
 ratings: {
   type: Number,
   default: 0,
 },
 images: [
   {
     public_id: {
       type: String,
       required: true,
     },
     url: {
       type: String,
       required: true,
     },
   },
 ],
 seller: {
   type: String,
   required: [true, "Please enter product seller"],
 },
 stock: {
   type: Number,
   required: [true, "Please enter product stock"],
   maxLength: [5, "Product name cannot exceed 5 characters"],
   default: 0,
 },
 numOfReviews: {
   type: Number,
   default: 0,
 },
 reviews: [
   {
     user: {
       type: mongoose.Schema.Types.ObjectId,
       required: true,
       ref: "User",
     },
     username: {
       type: String,
       required: true,
     },
     rating: {
       type: Number,
       required: true,
     },
     comment: {
       type: String,
       required: true,
     },
   },
 ],
 shop: {
   type: mongoose.Schema.ObjectId,
   //type: mongoose.Schema.Types.ObjectId,
   ref: "Shop",
   required: false,
 },
 user: {
   type: mongoose.Schema.ObjectId,
   //type: mongoose.Schema.Types.ObjectId,
   ref: "User",
   required: false,
 },
 createdAt: {
   type: Date,
   default: Date.now,
 },
});

module.exports = mongoose.model("Product", productSchema);

以下是我的店铺路线

const router = express.Router();


const { 


    getProductsByShopId,

} = require('../controllers/shopController');


//SHOP ROUTES

router.route('/shops/:shopId/products').get(getProductsByShopId);

module.exports = router;

在前端;这是我的商店Reducers页面?




   SHOP_PRODUCTS_REQUEST,
   SHOP_PRODUCTS_SUCCESS,
   SHOP_PRODUCTS_FAIL,

   CLEAR_ERRORS,
 } from '../constants/shopConstants';


export const shopProductsReducer = (state = { products: [] }, action ) => {
   switch(action.type) {
       case SHOP_PRODUCTS_REQUEST:
           return {
               ...state,
               loading: true,
               products: []
           }
           
       case SHOP_PRODUCTS_SUCCESS:
               
           return {
               ...state,
               loading: false,
               products: action.payload,
           } 
              
       case SHOP_PRODUCTS_FAIL:
           return {
               ...state,
               error: null
           }
       case CLEAR_ERRORS:
           return {
               ...state,
               error: null
           }

      default:
       return state 
   }
}

这又是我的店铺行动


import {


   SHOP_PRODUCTS_REQUEST,
   SHOP_PRODUCTS_SUCCESS,
   SHOP_PRODUCTS_FAIL,

   CLEAR_ERRORS,
 } from '../constants/shopConstants';



export const getProductsByShopId = (shopId) => async (dispatch) => {
   try{

       dispatch({ type: SHOP_PRODUCTS_REQUEST})

       const { data } = await axios.get(`/api/v1/shops/${shopId}/products`)

       dispatch({
           type: SHOP_PRODUCTS_SUCCESS,
           payload: data,
       })

   } catch (error) {
       dispatch({
           type: SHOP_PRODUCTS_FAIL,
           payload: error.response.data.message
       })
   }
}



 //Clear Errors
 export const clearErrors = () => async (dispatch) => {
   dispatch({
       type: CLEAR_ERRORS
   })
 }

这是 store.js 文件

import { thunk } from 'redux-thunk';
import { composeWithDevTools } from 'redux-devtools-extension'

import {  shopProductsReducer } from './reducers/shopReducers';
import { productsReducer, productDetailsReducer, } from './reducers/productReducers';

const reducer = combineReducers({
   shopProducts: shopProductsReducer,

})

let initialState = {}

const middleware = [thunk];
const store = createStore(reducer, initialState, composeWithDevTools(applyMiddleware(...middleware)))

export default store;

我的App.js文件

import Header from "./components/layout/Header";
import Footer from "./components/layout/Footer";
import shopProducts from './components/shop/ShopProducts'
import "./App.css";

function App() {
 return (
   <Router>
     <div className="App">
       <Header />
       <div className="big-container">
       <Routes>
         <Route path="/shops/:shopId/products" element={<ShopProducts />} exact />
       </Routes>

       </div>

       <Footer />
     </div>
   </Router>
 );
}

export default App;

最后,这是我想要呈现属于商店的产品的页面。

import Loader from '../layout/Loader';
import MetaData from '../layout/MetaData';
import { useAlert } from 'react-alert';
import { useDispatch, useSelector } from 'react-redux';
import { Link, useParams } from "react-router-dom";
import {  getProductsByShopId, clearErrors } from '../../actions/shopActions';

const ShopProducts = ({shopId}) => {
   const dispatch = useDispatch();
   const alert = useAlert();
   const params = useParams();

   const { loading, error,  products  } = useSelector(
       (state) => state.shopProducts
     );

   useEffect(() => {
       dispatch(getProductsByShopId(shopId));
       if (error) {
           alert.error(error);
           dispatch(clearErrors());
         }

   }, [dispatch, alert, error, shopId])
 return (
   <Fragment>
   {loading ? <Loader /> : (
       <Fragment>
       <div className='container wigdy'>
       <h1 className='heading'>Walmart products</h1>
       <div className='box-container pb-5'>
           {products && products.map((product) => (
                           <div className='box'>
                           <img src='/images/718BW18SfUL._AC_SY695_.jpg' />
                           <div className='mawords mb-3'>
                           <a href=''>{product.name}</a> 
                           <p>Ksh {product.price}</p>
                           <a href='' className='baton'>Add to cart</a>
                           </div>
                       </div>
           ))}

       </div>
   </div>
       </Fragment>
   )}
   </Fragment>
 )
}

export default ShopProducts
javascript reactjs node.js redux react-router-dom
1个回答
0
投票

假设所有 Redux 和后端代码都是正确的,我看到的问题是

ShopProducts
访问
shopId
用于向后端 API 发出 GET 请求。

给出以下路线声明:

<Route path="/shops/:shopId/products" element={<ShopProducts />} />

shopId
是一个路由路径参数,而不是传递给
ShopProducts
组件的 prop。通过路由组件中的
useParams
钩子访问它。

import { useAlert } from 'react-alert';
import { useDispatch, useSelector } from 'react-redux';
import { Link, useParams } from "react-router-dom";
import Loader from '../layout/Loader';
import MetaData from '../layout/MetaData';
import { getProductsByShopId, clearErrors } from '../../actions/shopActions';

const ShopProducts = () => {
  const dispatch = useDispatch();
  const alert = useAlert();

  const { shopId } = useParams(); // <-- access shopId from params

  const { loading, error,  products } = useSelector(
    (state) => state.shopProducts
  );

  // Fetch shop products when shop id changes
  useEffect(() => {
    dispatch(getProductsByShopId(shopId));
  }, [dispatch, shopId]);

  // Check for errors and alert separately
  useEffect(() => {
    if (error) {
      alert.error(error);
      dispatch(clearErrors());
    }
  }, [dispatch, alert, error]);

 return loading
   ? <Loader />
   : (
     <div className='container wigdy'>
       <h1 className='heading'>Walmart products</h1>
       <div className='box-container pb-5'>
         {products?.map((product) => (
           <div key={product.id} className='box'>
             <img src='/images/718BW18SfUL._AC_SY695_.jpg' />
             <div className='mawords mb-3'>
               <Link to='.....'>{product.name}</Link>
               <p>Ksh {product.price}</p>
               <Link to='.....' className='baton'>Add to cart</Link>
             </div>
           </div>
         ))}
       </div>
     </div>
   );
};

export default ShopProducts;
© www.soinside.com 2019 - 2024. All rights reserved.