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