按价格过滤产品的MERN堆栈不起作用



嗨,我正在使用redux的MERN堆栈构建电子商务应用程序。但有问题,当我试图发送价格数组参数在我的抓取功能。它给我的错误是XHR GET http://localhost:3000/api/v1/products?keyword=&page=1&price[gt]=undefined&price[lt]=undefined[HTTP/1.1 400错误请求12ms]。这是我的产品。jsx组件代码{success:false,消息:'资源未找到无效价格'}

import React, { useEffect, useState } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { Slider, Typography } from '@material-ui/core';
import { useAlert } from 'react-alert';
import { clearErrors, getProducts } from '../../actions/productActions';
import Loader from '../layout/Loader/Loader';
import ProductCard from '../Home/ProductCard';
import './Products.css';
import Pagination from 'react-js-pagination';
const Products = ({ match }) => {
const dispatch = useDispatch();
const alert = useAlert();
const [currentPage, setCurrentPage] = useState(1);
const [price, setPrice] = useState(0, 25000);
const { loading, products, productsCount, error, resultPerPage} =
useSelector((state) => state.products);
const keyword = match.params.keyword;
const setCurrentPageNo = (e) => {
setCurrentPage(e);
};
const priceHandler = (e, newPrice) => {
setPrice(newPrice);
};
useEffect(() => {
if (error) {
alert.error(error);
dispatch(clearErrors());
}
dispatch(getProducts(keyword, currentPage, price));
}, [dispatch, keyword, currentPage]);
return (
<>
{loading ? (
<Loader />
) : (
<>
<h2 className='productsHeading'>Products</h2>
<div className='products'>
{products &&
products.map((product) => (
<ProductCard key={product._id} product={product} />
))}
</div>
<div className='filterBox'>
<Typography>Price</Typography>
<Slider
value={price}
onChange={priceHandler}
valueLabelDisplay='auto'
aria-labelledby='range-slider'
min={0}
max={25000}
/>
</div>
{resultPerPage < productsCount && (
<div className='paginationBox'>
<Pagination
activePage={currentPage}
itemsCountPerPage={resultPerPage}
totalItemsCount={productsCount}
onChange={setCurrentPageNo}
nextPageText='Next'
prevPageText='Prev'
firstPageText='1st'
lastPageText='Last'
itemClass='page-item'
linkClass='page-link'
activeClass='pageItemActive'
activeLinkClass='pageLinkActive'
/>
</div>
)}
</>
)}
</>
);
};
export default Products;

这里是获取所有产品的操作

import axios from 'axios';
import {
ALL_PRODUCT_REQUEST,
ALL_PRODUCT_SUCCESS,
ALL_PRODUCT_FAIL,
PRODUCT_DETAILS_REQUEST,
PRODUCT_DETAILS_SUCCESS,
PRODUCT_DETAILS_FAIL,
CLEAR_ERRORS,
} from '../constants/productConstants';
export const getProducts =
(keyword = '', currentPage = 1, price = [0, 25000]) =>
async (dispatch) => {
try {
dispatch({
type: ALL_PRODUCT_REQUEST,
});
const { data } = await axios.get(
`/api/v1/products?keyword=${keyword}&page=${currentPage}&price[gt]=${price[0]}&price[lt]=${price[1]}`
);
dispatch({
type: ALL_PRODUCT_SUCCESS,
payload: data,
});
} catch (error) {
dispatch({
type: ALL_PRODUCT_FAIL,
payload: error.response.data.message,
});
}
};

Here is the Reducer for Products

export const productReducer = (state = { products: [] }, action) => {
switch (action.type) {
case ALL_PRODUCT_REQUEST:
return {
loading: true,
products: [],
};
case ALL_PRODUCT_SUCCESS:
return {
loading: false,
products: action.payload.products,
productsCount: action.payload.productsCount,
resultPerPage: action.payload.resultPerPage,
};
case ALL_PRODUCT_FAIL:
return {
loading: false,
error: action.payload,
};
case CLEAR_ERRORS:
return {
...state,
error: null,
};
default:
return state;
}
};

我正在使用自定义错误处理类,这里是这个

的代码
class ErrorResponse extends Error {
constructor(message, statusCode) {
super(message);
this.statusCode = statusCode;
Error.captureStackTrace(this, this.constructor);
}
}
module.exports = ErrorResponse;

中间件函数

const ErrorResponse = require('../utils/errorResponse');
const errorHandler = (err, req, res, next) => {
err.statusCode = err.statusCode || 500;
err.message = err.message || 'Internal Server Error';
// Wrong Mongodb Id error
if (err.name === 'CastError') {
const message = `Resource not found. Invalid: ${err.path}`;
err = new ErrorResponse(message, 400);
}
// Mongoose duplicate key error
if (err.code === 11000) {
const message = `Duplicate ${Object.keys(err.keyValue)} Entered`;
err = new ErrorResponse(message, 400);
}
// Wrong JWT error
if (err.name === 'JsonWebTokenError') {
const message = `Json Web Token is invalid, Try again `;
err = new ErrorResponse(message, 400);
}
// JWT EXPIRE error
if (err.name === 'TokenExpiredError') {
const message = `Json Web Token is Expired, Try again `;
err = new ErrorResponse(message, 400);
}
res.status(err.statusCode).json({
success: false,
message: err.message,
});
};
module.exports = errorHandler;

这是我的ApiFeatures类筛选,分页和排序

class ApiFeatures {
constructor(query, queryStr) {
this.query = query;
this.queryStr = queryStr;
}
search() {
const keyword = this.queryStr.keyword
? {
name: {
$regex: this.queryStr.keyword,
$options: 'i',
},
}
: {};
this.query = this.query.find({ ...keyword });
return this;
}
filter() {
const queryCopy = { ...this.queryStr };
//Removing fields
const removFields = ['keyword', 'page', 'limit'];
removFields.forEach((key) => delete queryCopy[key]);
let queryStr = JSON.stringify(queryCopy);
queryStr = queryStr.replace(/b(gt|gte|lt|lte)b/g, (key) => `$${key}`);
this.query = this.query.find(JSON.parse(queryStr));
return this;
}
pagination(resultPerPage) {
const currentPage = Number(this.queryStr.page) || 1;
const skip = resultPerPage * (currentPage - 1);
this.query = this.query.limit(resultPerPage).skip(skip);
return this;
}
}
module.exports = ApiFeatures;

这是我的控制器函数

const getProducts = asyncHandler(async (req, res, next) => {
const resultPerPage = 8;
const productsCount = await Product.countDocuments();
const apiFeatures = new ApiFeatures(Product.find(), req.query)
.search()
.filter()
.pagination(resultPerPage);
const products = await apiFeatures.query;
res.status(200).json({
success: true,
count: products.length,
productsCount,
resultPerPage,
products,
});
});

我的产品型号

const mongoose = require('mongoose');
const productSchema = mongoose.Schema({
name: {
type: String,
required: [true, 'Please Enter product Name'],
trim: true,
},
description: {
type: String,
required: [true, 'Please Enter product Description'],
},
price: {
type: Number,
required: [true, 'Please Enter product Price'],
maxLength: [8, 'Price cannot exceed 8 characters'],
},
ratings: {
type: Number,
default: 0,
},
images: [
{
public_id: {
type: String,
required: true,
},
url: {
type: String,
required: true,
},
},
],
category: {
type: String,
required: [true, 'Please Enter Product Category'],
},
Stock: {
type: Number,
required: [true, 'Please Enter product Stock'],
maxLength: [4, 'Stock cannot exceed 4 characters'],
default: 1,
},
numOfReviews: {
type: Number,
default: 0,
},
reviews: [
{
user: {
type: mongoose.Schema.ObjectId,
ref: 'User',
required: true,
},
name: {
type: String,
required: true,
},
rating: {
type: Number,
required: true,
},
comment: {
type: String,
required: true,
},
},
],
user: {
type: mongoose.Schema.ObjectId,
ref: 'User',
required: true,
},
createdAt: {
type: Date,
default: Date.now,
},
});
module.exports = mongoose.model('Product', productSchema);

我不知道是什么问题,因为我已经测试了这个api在邮差,它给出了正确的结果。帮我解决这个问题

乍一看,你发送请求的url是http://localhost:3000/api/v1/products?keyword=&page=1&price[gt]=undefined&price[lt]=undefined

我感觉问题是由发送undefined值产生的。

首先,在你的状态中初始化price为一个包含2个元素的数组。

const [price, setPrice] = useState([0, 25000]);
第二,确保你从过滤器 中得到正确的值
const priceHandler = (e, newPrice) => {
console.log(newPrice) // Maybe the value you need isn't being passed in the call
setPrice(newPrice);
};

同样,你可以检查动作中price的值,看看它是否真的是一个数组。

export const getProducts =
(keyword = '', currentPage = 1, price = [0, 25000]) =>
async (dispatch) => {
console.log(price) // and look at the value here
try {
dispatch({
type: ALL_PRODUCT_REQUEST,
});
const { data } = await axios.get(
`/api/v1/products?keyword=${keyword}&page=${currentPage}&price[gt]=${price[0]}&price[lt]=${price[1]}`
);
// Rest of the function ...
};

最新更新