I created a product reducer, product action, and home file along with constants file (mainly to name and store the type of the action). In Home
I was trying to get the products
from the backend that is already working.
I used dispatch
and useSelector
hooks for that function.
While I am using useSelector
hook in the Home
I am getting data as undefined. However when I checked by console logging in the action and the product file there the data is present.
I don't know why this error is happening.
Home.js
import React, { Fragment, useEffect } from 'react'
import Loader from "../layout/Loader/Loader";
import MetaData from "../layout/MetaData.js";
import ProductCard from './ProductCard.js';
import { CgMouse } from "react-icons/cg";
import "./Home.css";
import { clearErrors, getProduct } from "../../actions/productAction";
import { useSelector, useDispatch } from "react-redux";
const product = {
name: "Blue Tshirt",
images: [{ url: "https://i.ibb.co/DRST11n/1.webp" }],
price: "$3000",
_id: "aditya",
};
const Home = () => {
const dispatch = useDispatch();
useEffect(() => {
dispatch(getProduct())
}, [dispatch]);
const data = useSelector((state) => state.products);
console.log(data);
// const { loading, error, products } = useSelector((state) => state.products);
return (
<div>
{/* <Fragment>
{loading ? (
<Loader />
) : ( */}
<Fragment>
<MetaData title="ECOMMERCE" />
<div className="banner">
<p>WELCOME TO ECOMMERCE</p>
<h1>FIND AMAZING PRODUCTS BELOW</h1>
<a href="#container">
<button>
Scroll<CgMouse />
</button>
</a>
</div>
<h2 className="homeHeading">Featured Products</h2>
<div className="container" id="container">
{/* {products && products.map((product)=>( */}
<ProductCard key={product._id} product={product}/>
{/* ))} */}
</div>
</Fragment>
{/* )} */}
{/* </Fragment> */}
</div>
)
}
export default Home
ProductReducer.js
import {
ALL_PRODUCT_FAIL,
ALL_PRODUCT_REQUEST,
ALL_PRODUCT_SUCCESS,
CLEAR_ERRORS,
} from "../constants/productContants";
export const productReducer = (state = { products: [] }, action ) => {
// console.log(action.payload);
switch(action.type){
case ALL_PRODUCT_REQUEST:
return {
loading: true,
product: [],
};
case ALL_PRODUCT_SUCCESS:
let obj = {
loading: false,
products: action.payload.products,
productsCount: action.payload.productsCount,
resultPerPage: action.payload.resultPerPage,
filteredProductsCount: action.payload.filteredProductsCount,
};
// console.log(obj);
return obj;
case ALL_PRODUCT_FAIL:
return {
loading: false,
error: action.payload,
};
case CLEAR_ERRORS:
return {
...state,
error: null,
};
default:
return state;
}
};
productActions.js
import axios from "axios";
import {
ALL_PRODUCT_FAIL,
ALL_PRODUCT_REQUEST,
ALL_PRODUCT_SUCCESS,
CLEAR_ERRORS,
} from "../constants/productContants";
// get all the products
export const getProduct = () => async (dispatch) => {
try {
dispatch({type:ALL_PRODUCT_REQUEST});
const {data} = await axios.get("/api/v1/products");
dispatch({
type: ALL_PRODUCT_SUCCESS,
payload: data,
});
} catch(error) {
dispatch({
type: ALL_PRODUCT_FAIL,
payload: error.response.data.message,
});
};
}
Store.js
import { configureStore } from '@reduxjs/toolkit';
import { combineReducers } from "redux";
import { productReducer } from './reducers/productReducer';
import thunk from "redux-thunk";
const reducers = combineReducers({
product: productReducer,
});
let initalState = {};
const store = configureStore({
reducer: reducers,
initalState
});
export default store;
I was trying to fetch the data from backend and was using useSelector()
and useDispatch()
hook. The data is being fetched from the backend however while using useSelector()
I am getting that the data is undefined and I don't understand why this is happening.
const reducers = combineReducers({ product: productReducer, });
state.product
is the state the productReducer
provides, so if you are trying to access the products
array of the productReducer
then it should be state.product.products
.
const products = useSelector((state) => state.product.products);
or if you use object destructuring assignment
const { products } = useSelector((state) => state.product);
Alternatively, if this is the only state you could pass productReducer
directly to the store as the sole reducer, then state.products
would be correct.
const store = configureStore({
reducer: productReducer,
initalState
});
const products = useSelector((state) => state.products);