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
Related
The problem I'm facing my accidents array is empty for some reason, and receiving <h3>You have no accidents </h3>. console.log(accidents._id); this log returns undefined. Thank you in advance for the help and taking a look into this.
Slice:
import { createSlice, createAsyncThunk } from "#reduxjs/toolkit";
import accidentService from "./accidentService";
const initialState = {
accidents: [],
isError: false,
isSuccess: false,
isLoading: false,
message: "",
};
// Create new accident report
export const createAccident = createAsyncThunk(
"home/create",
async (accidentData, thunkAPI) => {
try {
const token = thunkAPI.getState().auth.user.token;
return await accidentService.createAccidentReport(accidentData, token);
} catch (error) {
const message =
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString();
return thunkAPI.rejectWithValue(message);
}
}
);
// Get accident reports
export const getAccidents = createAsyncThunk(
"accidents/getAll",
async (_, thunkAPI) => {
try {
const token = thunkAPI.getState().auth.user.token;
return await accidentService.getAccidents(token);
} catch (error) {
const message =
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString();
return thunkAPI.rejectWithValue(message);
}
}
);
export const accidentSlice = createSlice({
name: "accident",
initialState,
reducers: {
reset: (state) => initialState,
},
extraReducers: (builder) => {
builder
.addCase(createAccident.pending, (state) => {
state.isLoading = true;
})
.addCase(createAccident.fulfilled, (state, action) => {
state.isLoading = false;
state.isSuccess = true;
state.accidents.push(action.payload);
})
.addCase(createAccident.rejected, (state, action) => {
state.isLoading = false;
state.isError = true;
state.message = action.payload;
})
.addCase(getAccidents.pending, (state) => {
state.isLoading = true;
})
.addCase(getAccidents.fulfilled, (state, action) => {
state.isLoading = false;
state.isSuccess = true;
state.goals = action.payload;
})
.addCase(getAccidents.rejected, (state, action) => {
state.isLoading = false;
state.isError = true;
state.message = action.payload;
});
},
});
export const { reset } = accidentSlice.actions;
export default accidentSlice.reducer;
Service:
import axios from "axios";
const API_URL = "/api/home/accidentReport";
// Create new accident report
const createAccidentReport = async (accidentData, token) => {
//Get token
const config = {
headers: {
Authorization: `Bearer ${token}`,
},
};
const response = await axios.post(API_URL, accidentData, config);
return response.data;
};
//Get accident reports
const getAccidents = async (token) => {
//Get token
const config = {
headers: {
Authorization: `Bearer ${token}`,
},
};
const response = await axios.get("/api/home/allAccidents", config);
return response.data;
};
const accidentService = {
createAccidentReport,
getAccidents,
};
export default accidentService;
View:
import "./ReportTable.css";
import { useEffect } from "react";
import { useSelector, useDispatch } from "react-redux";
import { getAccidents } from "../../Features/accidentReport/accidentSlice";
const ReportTable = () => {
const dispatch = useDispatch();
const { accidents, isLoading, isError, message } = useSelector(
(state) => state.accident
);
useEffect(() => {
dispatch(getAccidents());
}, [dispatch, getAccidents]);
console.log(accidents._id);
return (
<>
<section>
{accidents.length > 0 ? (
<div>
{accidents.map((accident) => (
<p key={accident._id}>{accident._id}</p>
))}
</div>
) : (
<h3>You have no accidents </h3>
)}
</section>
</>
);
};
export default ReportTable;
In my fullfilled i am getting response as undefined. any one please help?
code :
import { createAsyncThunk, createSlice } from "#reduxjs/toolkit";
import axios from "axios";
const fetchPost = createAsyncThunk('fetch/post', async (params: string) => {
try {
const { data } = await axios.get('https://registry.npmjs.org/-/v1/search', { params: { text: params } })
data.objects.map((result: any) => {
console.log('result', result)//getting result
return result.package.name;
});
} catch (err: any) {
return err?.response;
}
})
interface RepositoriesState {
loading: boolean;
error: string | null;
data: string[];
}
const initialRepoState:RepositoriesState = {
loading: false,
error: null,
data:[]
}
const repositorySlice = createSlice({
name: 'repo-slice',
initialState: initialRepoState,
reducers: {},
extraReducers: (builder) => {
builder
.addCase(fetchPost.pending, (state) => {
state.loading = true
})
.addCase(fetchPost.fulfilled, (state, action) => {
state.loading = false;
state.data = action.payload;
console.log('payload', action.payload) //undefined
})
.addCase(fetchPost.rejected, (state) => {
state.loading = false;
state.error = "error in api";
state.data = [];
})
}
})
export { fetchPost };
export default repositorySlice.reducer;
Nothing is getting returned from your function... so its undefined
I guess it should be as so
const fetchPost = createAsyncThunk('fetch/post', async (params: string) => {
try {
const { data } = await axios.get('https://registry.npmjs.org/-/v1/search', { params: { text: params } })
return data.objects.map((result: any) => {
console.log('result', result)//getting result
return result.package.name;
});
} catch (err: any) {
return err?.response;
}
})
I have a problem with React redux. And I want to display the current state immediately. Unfortunately this doesn't work as intended. The changed data is only displayed correctly after the page has been reloaded.
This is the Main Part in my Articel.js
const buySomething = async (articelId) => {
await axios.put(`/articel/request/${articelId}`).then((res) => {
dispatch(requested(currentUser._id));
setSnackbarMessage(res.data);
setOpen(true);
});
};
Articel model:
requested: {
type: [String],
default: [],
},
articelSlice.js
const initialState = {
currentArticel: null,
loading: false,
error: false,
};
requested: (state, action) => {
if (!state.currentArticel.requested.includes(action.payload)) {
state.currentArticel.requested.push(action.payload);
} else {
state.currentArticel.requested.splice(
state.currentArticel.requested.findIndex(
(userId) => userId === action.payload
),
1
);
}
},
Complete articelSlice Code:
import { createSlice } from "#reduxjs/toolkit";
const initialState = {
currentArticel: null,
loading: false,
error: false,
};
export const articelSlice = createSlice({
name: "articel",
initialState,
reducers: {
fetchStart: (state) => {
state.loading = true;
},
fetchSuccess: (state, action) => {
state.loading = false;
state.currentArticel = action.payload;
},
fetchFailure: (state) => {
state.loading = false;
state.error = true;
},
requested: (state, action) => {
if (!state.currentArticel.requested.includes(action.payload)) {
state.currentArticel.requested.push(action.payload);
} else {
state.currentArticel.requested.splice(
state.currentArticel.requested.findIndex(
(userId) => userId === action.payload
),
1
);
}
},
like: (state, action) => {
if (!state.currentArticel.likes.includes(action.payload)) {
state.currentArticel.likes.push(action.payload);
state.currentArticel.dislikes.splice(
state.currentArticel.dislikes.findIndex(
(userId) => userId === action.payload
),
1
);
}
},
dislike: (state, action) => {
if (!state.currentArticel.dislikes.includes(action.payload)) {
state.currentArticel.dislikes.push(action.payload);
state.currentArticel.likes.splice(
state.currentArticel.likes.findIndex(
(userId) => userId === action.payload
),
1
);
}
},
},
});
export const {
fetchStart,
fetchSuccess,
fetchFailure,
like,
dislike,
requested,
} = articelSlice.actions;
export default articelSlice.reducer;
I am learning react with redux-toolkit. I am stuck with some actions there.
I want to add quantity in Cart, so if I add same item more than once it should be like X1/x2/x3...etc.
And I want to delete items/item but only with the same ID ( when I click delete only delete that one ex. APPLE)
import { createSlice } from "#reduxjs/toolkit";
const initialState = {
hidden: true,
cartItems: 0,
itemsInCart: [],
quantity: 0,
totalCount: 0,
};
export const cartSlice = createSlice({
name: "cart",
initialState,
reducers: {
removeItem: (state, action) => {},
removeAll: (state) => {
state.cartItems = 0;
state.itemsInCart = [];
state.totalCount = 0;
},
addToCart(state, action) {
state.itemsInCar = state.itemsInCart.push(action.payload);
state.cartItems += 1;
state.totalCount += action.payload.price;
},
showCart: (state) => {
state.hidden = !state.hidden;
},
},
});
export const { showCart, addToCart, removeAll, removeItem } = cartSlice.actions;
export default cartSlice.reducer;
addToCart: (state, action) => {
const itemInCart = state.cart.find((item) => item.id === action.payload.id);
if (itemInCart) {
itemInCart.quantity++;
} else {
state.cart.push({ ...action.payload, quantity: 1 });
}
},
I am trying to add a product to the cart.
I don't understand why the state is undefined,
I have a localStorage 'cart' :
(3) [{…}, {…}, {…}]
0: {product: {…}, quantity: 1}
1: {product: {…}, quantity: 2}
console.log(action.payload):
{product: {…}, quantity: 1}
When I clicked the add cart button, my localStorage added correctly but the state was automatically lost
My code cartSlice.js:
import { createSlice } from '#reduxjs/toolkit';
import {
createCart,
getCart,
updateCart,
deleteCart
} from './../asyncActions/cart.asyncAction';
var data = JSON.parse(localStorage.getItem('cart'));
const cartSlice = createSlice({
name: 'cart',
initialState: {
cart: data ? data : [],
searchValue: '',
},
reducers: {
},
extraReducers: {
//* get cart
[getCart.pending]: (state, action) => {
},
[getCart.fulfilled]: (state, action) => {
if (action.payload) {
state.cart = action.payload;
}
},
[getCart.rejected]: (state, action) => {
},
// create
[createCart.pending]: (state, action) => {
},
[createCart.fulfilled]: (state, action) => {
if (action.payload) {
let idProductAction = action.payload.product.id;
var index = state.cart ? state.cart.map((item) => item.product.id).indexOf(idProductAction) : -1;
if(index !== -1){
state.cart[index].quantity += action.payload.quantity;
} else {
state.cart = [action.payload, ...state.cart];
}
state.cart = localStorage.setItem('cart', JSON.stringify(state.cart));
}
},
[createCart.rejected]: (state, action) => {
console.log('sai');
},
}
});
const { actions, reducer } = cartSlice;
const { clearStateCart } = actions;
export { clearStateCart };
export default reducer;
My code component Cart.js:
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { getCart, createCart } from '../../store/asyncActions/cart.asyncAction';
function Cart(props) {
const classes = useStyles();
const dispatch = useDispatch();
let cart = useSelector((state) => state.cart.cart);
let productList = useSelector((state) => state.products.products);
const addCart = (product) => {
getDispatchCreateCart(product);
}
const getDispatchCreateCart = (product) => {
dispatch (
createCart({
product: product,
quantity: 1
})
)
}
const getDispatchProducts = () => {
dispatch (
getProducts()
)
}
const getDispatchGetCart = () => {
dispatch (
getCart()
)
}
useEffect(() => {
getDispatchProducts();
getDispatchGetCart();
}, []);
return (...);
}
export default Cart;
my redux devtools show:
cart/createCart/pedding : state cart has data.
enter image description here
cart/createCart/fulfilled : state cart undefined.
enter image description here
I don't understand why the state is undefined,
Hope everybody help please.
You can not state.cart, It will be lost by localStorage typeof undefined:
state.cart = localStorage.setItem('cart', JSON.stringify(state.cart));
Edit:
[createCart.fulfilled]: (state, action) => {
if (action.payload) {
let idProductAction = action.payload.product.id;
var index = state.cart ? state.cart.map((item) => item.product.id).indexOf(idProductAction) : -1;
if(index !== -1){
state.cart[index].quantity += action.payload.quantity;
} else {
state.cart = [action.payload, ...state.cart];
}
localStorage.setItem('cart', JSON.stringify(state.cart));
}
},