I guess what happening is use Effect is trying to load rating or the component before the request is fetched in async await that is too slow and ratings recieved after use Effect runs it says rating is undefined !!!!! idk what i should do now i ve tried so many things. pls help?
My Product.js
import React, { Fragment, useEffect, useState } from "react";
import { useParams } from "react-router-dom";
import Pagination from "react-js-pagination";
import "./Products.css";
import { useSelector, useDispatch } from "react-redux";
import { clearErrors, getProduct } from "../../actions/productAction";
import Loader from "../layout/Loader/Loader";
import ProductCard from "../Home/ProductCard";
import Slider from "@material-ui/core/Slider";
import Typography from "@material-ui/core/Typography";
import { useAlert } from "react-alert";
import Metadata from "../layout/Metadata";
const categories = [
"Laptop",
"Footwear",
"Bottom",
"Tops",
"Attire",
"Camera",
"phone",
];
const Products = () => {
const dispatch = useDispatch();
const alert = useAlert();
const { keyword } = useParams();
const [currentPage, setCurrentPage] = useState(1);
const [price, setPrice] = useState([0, 25000]);
const [category, setCategory] = useState("");
const [ratings, setRatings] = useState(0);
const {
loading,
error,
products,
productsCount,
resultPerPage,
filteredProductsCount,
} = useSelector((state) => state.products);
// const keyword = match.params.keyword;
const setCurrentPageNo = (e) => {
setCurrentPage(e);
};
const priceHandler = (event, newPrice) => {
setPrice(newPrice);
};
let count = filteredProductsCount;
useEffect(() => {
if (error) {
alert.error(error);
dispatch(clearErrors());
}
dispatch(getProduct(keyword, currentPage, price, category, ratings));
}, [dispatch, keyword, currentPage, price, category, ratings, alert, error]);
return (
<Fragment>
{loading ? (
<Loader />
) : (
<Fragment>
<Metadata title="ECOMMERCE" />
<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}
/>
<Typography>Categories</Typography>
<ul className="categoryBox">
{categories.map((category) => (
<li
className="category-link"
key={category}
onClick={() => setCategory(category)}
>
{category}
</li>
))}
</ul>
<fieldset>
<Typography component="legend">Ratings Above</Typography>
<Slider
defaultValue={ratings}
onChange={(e, newRating) => {
setRatings(newRating);
}}
aria-labelledby="continuous-slider"
valueLabelDisplay="auto"
min={0}
max={5}
marks={true}
/>
</fieldset>
</div>
{resultPerPage < count && (
<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>
)}
</Fragment>
)}
</Fragment>
);
};
export default Products;
My productAction
import axios from "axios";
import {
ALL_PRODUCT_REQUEST,
ALL_PRODUCT_SUCCESS,
ALL_PRODUCT_FAIL,
CLEAR_ERRORS,
PRODUCT_DETAILS_REQUEST,
PRODUCT_DETAILS_SUCCESS,
PRODUCT_DETAILS_FAIL,
} from "../constants/productConstants";
export const getProduct =
(keyword = "", currentPage = 1, price = [0, 25000], category, ratings = 0) =>
async (dispatch) => {
try {
dispatch({ type: ALL_PRODUCT_REQUEST });
let link = `/api/v1/products?keyword=${keyword}&page=${currentPage}&price[gte]=${price[0]}&price[lte]=${price[1]}&ratings[gte]=${ratings}`;
if (category) {
link = `/api/v1/products?keyword=${keyword}&page=${currentPage}&price[gte]=${price[0]}&price[lte]=${price[1]}&category=${category}&ratings[gte]=${ratings}`;
}
const { data } = await axios.get(link);
dispatch({
type: ALL_PRODUCT_SUCCESS,
payload: data,
});
} catch (error) {
dispatch({
type: ALL_PRODUCT_FAIL,
payload: error.response.data.message,
});
}
};
export const getProductDetails = (id) => async (dispatch) => {
try {
dispatch({ type: PRODUCT_DETAILS_REQUEST });
const { data } = await axios.get(`/api/v1/product/${id}`);
dispatch({
type: PRODUCT_DETAILS_SUCCESS,
payload: data.product,
});
} catch (error) {
dispatch({
type: PRODUCT_DETAILS_FAIL,
payload: error.response.data.message,
});
}
};
//Clearing Errors
export const clearErrors = () => async (dispatch) => {
dispatch({ type: CLEAR_ERRORS });
};
My productReducer
import {
ALL_PRODUCT_REQUEST,
ALL_PRODUCT_SUCCESS,
ALL_PRODUCT_FAIL,
CLEAR_ERRORS,
PRODUCT_DETAILS_REQUEST,
PRODUCT_DETAILS_SUCCESS,
PRODUCT_DETAILS_FAIL,
} from "../constants/productConstants";
export const productsReducer = (state = { products: [] }, action) => {
switch (action.type) {
case ALL_PRODUCT_REQUEST:
return {
loading: true,
product: [],
};
case ALL_PRODUCT_SUCCESS:
return {
loading: false,
products: action.payload.products,
productsCount: action.payload.productCount,
resultPerPage: action.payload.resultPerPage,
filteredProductsCount: action.payload.filteredProductsCount,
};
case ALL_PRODUCT_FAIL:
return {
loading: false,
error: action.payload,
};
//...state meand access everything present in the state object
case CLEAR_ERRORS:
return {
...state,
error: null,
};
default:
return state;
}
};
export const productsDetailsReducer = (state = { product: {} }, action) => {
switch (action.type) {
case PRODUCT_DETAILS_REQUEST:
return {
loading: true,
...state,
};
case PRODUCT_DETAILS_SUCCESS:
return {
loading: false,
product: action.payload,
};
case PRODUCT_DETAILS_FAIL:
return {
loading: false,
error: action.payload,
};
case CLEAR_ERRORS:
return {
...state,
error: null,
};
default:
return state;
}
};