Reputation: 191
I'm pretty new to react, and I working on a product where I am trying to get the number of individual ratings of a product from the total number of reviews. This is in my front end in my productScreen.js:
const getNumRating = (num) => product.reviews.filter((x) => x.rating === num).length;
The problem that I'm having is that every once in awhile I'm get a Uncaught TypeError: Cannot read properties of undefined (reading 'reviews')
error on this line. Reviews comes from reviews: [reviewSchema]
in my productModel.js.
I'm unsure as to why I'm getting this. In the return ();
portion of my productScreen.js document, I have:{product.reviews.map((review) => (... ))}
, which works fine.
Could I not be passing reviews from my backend to my fronted?
This is my ProductRouter.js document:
import express from 'express';
import expressAsyncHandler from 'express-async-handler';
import data from '../data.js';
import Product from '../models/productModel.js';
import { isAdmin, isAuth, isSellerOrAdmin } from '../utils.js';
const productRouter = express.Router();
productRouter.get(
'/seed',
expressAsyncHandler(async (req, res) => {
// await Product.remove({});
const createdProducts = await Product.insertMany(data.products);
res.send({ createdProducts });
})
);
productRouter.get(
'/:id',
expressAsyncHandler(async (req, res) => {
const product = await Product.findById(req.params.id);
if (product) {
res.send(product);
} else {
res.status(404).send({ message: 'Product Not Found' });
}
})
);
productRouter.post(
'/',
isAuth,
isSellerOrAdmin,
expressAsyncHandler(async (req, res) => {
const product = new Product({
name: 'sample name ' + Date.now(),
});
const createdProduct = await product.save();
res.send({ message: 'Product Created', product: createdProduct });
})
);
productRouter.put(
'/:id',
isAuth,
isSellerOrAdmin,
expressAsyncHandler(async (req, res) => {
const productId = req.params.id;
const product = await Product.findById(productId);
if (product) {
product.name = req.body.name;
const updatedProduct = await product.save();
res.send({ message: 'Product Updated', product: updatedProduct });
} else {
res.status(404).send({ message: 'Product Not Found' });
}
})
);
productRouter.delete(
'/:id',
isAuth,
isAdmin,
expressAsyncHandler(async (req, res) => {
const product = await Product.findById(req.params.id);
if (product) {
const deleteProduct = await product.remove();
res.send({ message: 'Product Deleted', product: deleteProduct });
} else {
res.status(404).send({ message: 'Product Not Found' });
}
})
);
productRouter.post(
'/:id/reviews',
isAuth,
expressAsyncHandler(async (req, res) => {
const productId = req.params.id;
const product = await Product.findById(productId);
if (product) {
if (product.reviews.find((x) => x.name === req.user.name)) {
return res
.status(400)
.send({ message: 'You already submitted a review' });
}
const review = {
name: req.user.name,
rating: Number(req.body.rating),
comment_title: req.body.comment_title,
comment: req.body.comment,
age: req.body.age,
customerImages: req.body.customerImages,
};
product.reviews.push(review);
product.numReviews = product.reviews.length;
product.rating =
product.reviews.reduce((a, c) => a = a +c.rating, 0) /
product.reviews.length;
const updatedProduct = await product.save();
res.status(201).send({
message: 'Review Created',
review: updatedProduct.reviews[updatedProduct.reviews.length - 1],
});
} else {
res.status(404).send({ message: 'Product Not Found' });
}
})
);
export default productRouter;
I also tried to add numRating5
to my productModel.js, and
product.numRating5 = product.reviews.filter((x) => x.rating === 5).length;
after product.rating
in productRouter.post(...)
in productRouter.js, but that just gave me an Uncaught TypeError: Cannot read properties of undefined (reading 'numRating5')
error in the frontend.
I would really appreciate any help or advice on how to fix this. Thank you!
Upvotes: 0
Views: 1579
Reputation: 13284
The problem is probably related to the fact that the product
has not been loaded from the API when you are trying to access it.
Adding a null-check should prevent the error:
const getNumRating = (num) => {
if (!product) return 0;
return product.reviews.filter((x) => x.rating === num).length;
}
Upvotes: 2