hello everyone I am aking a MERN project and Im running into a peobleme. so Im using redux toolkit slice and when I try to dispatch the fetchProduct like so
import React, { useEffect, useState } from "react";
import "./products.css";
import { useSelector, useDispatch } from "react-redux";
import { DataGrid } from "@mui/x-data-grid";
import { Link, Navigate } from "react-router-dom";
import DeleteForeverIcon from "@mui/icons-material/DeleteForever";
import Loader from "components/Loader";
import { Button } from "@mui/material";
import { useNavigate } from "react-router-dom";
import Message from "components/Message";
import { fetchProducts } from "slices/productSlice";
const Products = () => {
const dispatch = useDispatch();
const navigate = useNavigate();
const { loading, error, products } = useSelector((state) => state.product);
useEffect(() => {
dispatch(fetchProducts());
}, [dispatch]);
const columns = [
{ field: "_id", hide: true },
{
field: "name",
flex: 1,
headerName: "Product",
width: 200,
renderCell: (params) => {
return (
<div className="productListItem">
<img className="productListImg" src={params.row.image} alt="" />
{params.row.name}
</div>
);
},
},
{ field: "countInStock", headerName: "Stock", flex: 1 },
{
field: "price",
headerName: "Price",
flex: 1,
},
{
field: "brand",
headerName: "Brand",
flex: 1,
},
{
field: "action",
headerName: "Action",
flex: 1,
renderCell: (params) => {
return (
<>
<Link to={"/products/" + params.row._id}>
<button className="productListEdit">Edit</button>
</Link>
<DeleteForeverIcon
className="productListDelete"
// onClick={() => deleteHandler(params.row._id)}
/>
</>
);
},
},
];
return (
<div style={{ height: "90vh" }}>
{loading ? (
<Loader />
) : error ? (
<Message variant="error" />
) : (
<DataGrid
height={100}
getRowId={(row) => row._id}
rows={products?.products}
disableSelectionOnClick
columns={columns}
rowsPerPageOptions={[10, 15, 20]}
pageSize={10}
checkboxSelection
/>
)}
</div>
);
};
export default Products;
the data never get fetched and I get this error in the browser:
"Warning: Failed prop type: The prop rows
is marked as required in ForwardRef(DataGrid)
, but its value is undefined
."
but when I remove what's inside the return of the componenet and add just an h1 tag the data get fetched and I can find it in redux store states
this is the slice I am working with :
import axios from 'axios';
import { createSlice } from '@reduxjs/toolkit';
const initialState = {
products: [],
loading: false,
error: null
};
const baseurl = "http://localhost:5001"
const productSlice = createSlice({
name: 'product',
initialState,
reducers: {
fetchProductsStart(state) {
state.loading = true;
},
fetchProductsSuccess(state, action) {
state.products = action.payload;
state.loading = false;
state.error = null;
},
fetchProductsError(state, action) {
state.loading = false;
state.error = action.payload;
},
deleteProductStart(state) {
state.loading = true;
},
deleteProductSuccess(state, action) {
state.products = state.products.filter(product => product._id !== action.payload);
state.loading = false;
state.error = null;
},
deleteProductError(state, action) {
state.loading = false;
state.error = action.payload;
},
updateProductStart(state) {
state.loading = true;
},
updateProductSuccess(state, action) {
const index = state.products.findIndex(product => product._id === action.payload._id);
state.products[index] = action.payload;
state.loading = false;
state.error = null;
},
updateProductError(state, action) {
state.loading = false;
state.error = action.payload;
},
fetchProductStart(state) {
state.loading = true;
},
fetchProductSuccess(state, action) {
state.products = [action.payload];
state.loading = false;
state.error = null;
},
fetchProductError(state, action) {
state.loading = false;
state.error = action.payload;
}
}
});
export const {
fetchProductsStart,
fetchProductsSuccess,
fetchProductsError,
deleteProductStart,
deleteProductSuccess,
deleteProductError,
updateProductStart,
updateProductSuccess,
updateProductError,
fetchProductStart,
fetchProductSuccess,
fetchProductError
} = productSlice.actions;
export default productSlice.reducer
export const fetchProducts = () => async dispatch => {
try {
dispatch(fetchProductsStart());
const response = await axios.get(`${baseurl}/products`);
dispatch(fetchProductsSuccess(response.data));
} catch (error) {
dispatch(fetchProductsError(error.message));
}
};
export const deleteProduct = id => async dispatch => {
try {
dispatch(deleteProductStart());
await axios.delete(`${baseurl}/products/${id}`);
dispatch(deleteProductSuccess(id));
} catch (error) {
dispatch(deleteProductError(error.message));
}
};
export const updateProduct = product => async dispatch => {
try {
dispatch(updateProductStart());
const response = await axios.patch(`${baseurl}/products/${product._id}`, product);
dispatch(updateProductSuccess(response.data));
} catch (error) {
dispatch(updateProductError(error.message));
}
};
so what am I doing wrrong here
the modified Slice
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
const initialState = {
products: [],
loading: 'idle',
error: null
};
const baseurl = 'http://localhost:5001';
export const fetchProducts = createAsyncThunk(
'products/fetchProducts',
async () => {
const response = await axios.get(`${baseurl}/products`);
return response.data;
}
);
export const deleteProduct = createAsyncThunk(
'products/deleteProduct',
async id => {
await axios.delete(`${baseurl}/products/${id}`);
return id;
}
);
export const updateProduct = createAsyncThunk(
'products/updateProduct',
async product => {
const response = await axios.patch(
`${baseurl}/products/${product._id}`,
product
);
return response.data;
}
);
export const fetchProduct = createAsyncThunk(
'products/fetchProduct',
async id => {
const response = await axios.get(`${baseurl}/products/${id}`);
return response.data;
}
)
const productSlice = createSlice({
name: 'products',
initialState,
reducers: {},
extraReducers: {
[fetchProducts.pending]: state => {
state.loading = 'pending';
},
[fetchProducts.fulfilled]: (state, action) => {
state.loading = 'idle';
state.products = action.payload;
},
[fetchProducts.rejected]: (state, action) => {
state.loading = 'idle';
state.error = action.error.message;
},
[deleteProduct.pending]: state => {
state.loading = 'pending';
},
[deleteProduct.fulfilled]: (state, action) => {
state.loading = 'idle';
state.products = state.products.filter(product => product._id !== action.payload);
},
[deleteProduct.rejected]: (state, action) => {
state.loading = 'idle';
state.error = action.error.message;
},
[updateProduct.pending]: state => {
state.loading = 'pending';
},
[updateProduct.fulfilled]: (state, action) => {
state.loading = 'idle';
const index = state.products.findIndex(product => product._id === action.payload._id);
state.products[index] = action.payload;
},
[updateProduct.rejected]: (state, action) => {
state.loading = 'idle';
state.error = action.error.message