Add to cart in redux-toolkit (state undefined), Someone, please help me? - reactjs

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));
}
},

Related

useSelector does not update the value after dispatch

I do not understand, the value is dispatch but useSelector does not update, it's only showing an empty value.
In the above image, the cart contains the value.
see this above image, console Array does not contain any values.
Code:
const dispatch = useDispatch();
const selectorCart = useSelector((state) => state.cart);
const selectorLogin = useSelector((state) => state.login);
function handleAddItemInCart(product) {
let isProductAllReadyExit = true;
for(let item of selectorCart) {
if (product.id === item.id && product.title === item.title) {
isProductAllReadyExit = false;
break;
}
}
if (isProductAllReadyExit) {
dispatch(addItemInCart(product));
console.log("2. Selector Cart Value : ", selectorCart);
handleAddCartItemSave();
}
cartslice
import { createSlice } from "#reduxjs/toolkit";
const cartSlice = createSlice({
name: "cart",
initialState: [],
reducers : {
addItemInCart : (state, action) => {
state.push(action.payload);
},
removeItemInCart : (state, action) => {
return state.product.filter(product => product.id !== action.payload && product.title !== action.payload.title);
},
},
});
export const {addItemInCart, removeItemInCart} = cartSlice.actions;
export default cartSlice.reducer;
What is this mistake in the above code?

Best way to share state between slices in redux toolkit?

If I have a slice like this
cartSlice.js
import { createSlice } from "#reduxjs/toolkit";
import cartItems from "../cartItems";
const initialState = {
cartItems: cartItems,
amount: 1,
total: 0,
isLoading: true,
};
export const cartSlice = createSlice({
name: "cart",
initialState,
reducers: {
clearCart: (store) => {
store.cartItems = [];
},
removeItem: (store, action) => {
store.cartItems = store.cartItems.filter(
(item) => item.id !== action.payload
);
},
increase: (store, action) => {
const target_item = store.cartItems.find(
(item) => item.id === action.payload.id
);
target_item.amount++;
},
decrease: (store, { payload }) => {
const target_item = store.cartItems.find(
(item) => item.id === payload.id
);
target_item.amount--;
},
calculate: (store) => {
let amount = 0;
let total = 0;
store.cartItems.forEach((item) => {
amount += item.amount;
total += item.amount * item.price;
});
store.amount = amount;
store.total = total;
},
},
});
export const { clearCart, removeItem, increase, decrease, calculate } =
cartSlice.actions;
export default cartSlice.reducer;
How do I implement something like this?
checkoutSlice.js
const initialState = {
purchasedItems: [],
checkoutIsOpen: false,
};
const { cartItems, amount } = useSelector((store) => store.cart); <--HYPOTHETICALLY
const checkoutSlice = createSlice({
name: "checkout",
initialState,
reducers: {
addToCheckout: (state) => {
if (amount >= 1) { <------HERE
state.purchasedItems.push(cartItems); <---HERE
}
},
openCheckout: (state) => {
state.checkoutIsOpen = true;
},
},
});
export const { addToCheckout, openCheckout } = checkoutSlice.actions;
export default checkoutSlice.reducer;
You can't use selectors, what else is left? I've read a ton of previous posts that say it's not possible, but then how do you create functional websites with components that interact with each other? Like in this case with basic shopping app with a checkout cart, how do you get the selected items into the checkout cart? It's just not possible? That doesn't make sense because isn't that basic core functionality of a website? Why wouldn't redux allow this? I feel like there has to be a way.
I think I'm fundamentally misunderstanding here.
Any help? How do I accomplish this?

React - Redux-Toolkit items in cart

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 });
}
},

Redux Action is Dispatched but state not updating accordingly

When i click the delete button the action(removeBus) is dispatched and the correct payload value is sent however the store is not updating
here is my busSlice file
import { createSlice } from "#reduxjs/toolkit";
const initialState = [
{
id: "0",
description: "bus1"
},
{
id: "1",
description: "bus2"
}
];
const busSlice = createSlice({
name: "bus",
initialState,
reducers: {
removeBus: (state, action) => {
state.filter((bus) => bus.id !== action.payload);
console.log(action.payload);
}
}
});
export const { removeBus } = busSlice.actions;
export default busSlice.reducer;
here is where i created and export the store
import { configureStore } from "#reduxjs/toolkit";
import busReducer from "../features/busSlice";
export const store = configureStore({
reducer: {
busses: busReducer
}
});
the component that uses the state is created in the following code and App is wrapped inside a redux provider Component and the above store is provided as a props in index.js
import "./styles.css";
import { useSelector, useDispatch } from "react-redux";
import { removeBus } from "./features/busSlice";
export default function App() {
const dispatch = useDispatch();
const busses = useSelector((state) => state.busses);
const handleRemove = (id) => {
dispatch(removeBus(id));
};
return (
<div className="App">
{busses.map((bus) => (
<ul>
<li key={bus.id}>
<p>{bus.description}</p>
<button onClick={() => handleRemove(bus.id)}>delete</button>
</li>
</ul>
))}
</div>
);
}
using redux dev tools i can see an action busses\removeBus is dispatched with the appropriate payload value but nothing is happening to the state.
You can change:
removeBus: (state, action) => {
state.filter((bus) => bus.id != action.payload);
console.log(action.payload);
}
can be the data types of bus.id and action.payload are different.
you are not updating state correctly you need to say change my state to filtered state
like this
removeBus(state, action){
state = state.filter((bus) => bus.id !== action.payload);
console.log(action.payload);
}
I also had this issue.
I my case, code looked like this:
const someSlice = createSlice({
name: 'test',
initialState: null,
reducers: {
addData(state, action) {
state = action.payload
}
}
});
This did not work
const someSlice = createSlice({
name: 'test',
initialState: null,
reducers: {
addData(state, action) {
state = action.payload;
return state;
}
}
});
this worked.
But this is very strange, should not work this way.
You need to return your updated states
import { createSlice } from "#reduxjs/toolkit";
const initialState = [
{
id: "0",
description: "bus1"
},
{
id: "1",
description: "bus2"
}
];
const busSlice = createSlice({
name: "bus",
initialState,
reducers: {
removeBus: (state, action) => {
state = state.filter((bus) => bus.id !== action.payload);
return state;
}
}
});
export const { removeBus } = busSlice.actions;
export default busSlice.reducer;

cannot update initalState in redux-toolkit with createAsyncThunk

Im trying to set and update initialState in redux toolkit after fetch operation
pageSlice.js
import { createSlice, createAsyncThunk } from "#reduxjs/toolkit";
import { deletePage, getPages, savePage, updatePage } from "../../services/page.service";
import { initialPage } from "../../components";
export const getUserPages = createAsyncThunk(
"pages/getUserPages",
async() => {
const pages = await getPages();
return pages
}
)
export const saveUserPage = createAsyncThunk(
"pages/saveUserPage",
async(page) => {
const savedPage = await savePage(page);
return savedPage;
}
)
export const pageSlice = createSlice({
name: "pages",
initialState: {
pageStatus: "idle",
pages: []
},
reducers: {},
extraReducers: {
[getUserPages.pending]: (state) => {
state.pageStatus = "loading";
},
[getUserPages.fulfilled]: (state, action) => {
state.pages = action.payload
state.pageStatus = "pageLoaded"
},
[getUserPages.rejected]: (state) => {
state.pageStatus = "error"
},
[saveUserPage.pending]: (state) => {
state.pageStatus = "loading";
},
[saveUserPage.fulfilled]: (state, action) => {
state.pages.push(action.payload)
state.pageStatus = "pageLoaded"
},
[saveUserPage.rejected]: (state) => {
state.pageStatus = "error"
}
}
})
export default pageSlice.reducer;
initialState: {
pageStatus: "idle",
pages: []
},
Working on note app with redux-toolkit. pages array will contain array of objects.
In extraReducers
[saveUserPage.fulfilled]: (state, action) => {
// console.log(state.pages) if empty( undefined ) else [{element}]
state.pages.push(action.payload)
state.pageStatus = "pageLoaded"
}
if initailState pages array contain any single element [saveUserPage.fulfilled] work fine.
but if array is empty then i get error
Cannot read property 'push' of undefined at pages/saveUserPage/fulfilled
if console.log(state.pages) in s
What I'm doing wrong ?
Based on the Error message you have mentioned Cannot read property 'push' of undefined at pages/saveUserPage/fulfilled, state.pages is not an empty array, It is undefined. That is the reason you are seeing this error.
Array.push operation, all it expects the variable to be array i.e. [], It doesn't matter whether it is empty or it has items.
Please check the below code block or some other operation, whether it is assigning it as 'undefined' in the first place.
[getUserPages.fulfilled]: (state, action) => {
state.pages = action.payload
state.pageStatus = "pageLoaded"
},
Workaround solution:
[saveUserPage.fulfilled]: (state, action) => {
if(state.pages === undefined){
state.pages = [];
if(action.payload && action.payload.length > 0){ / Make sure that payload is an array
state.pages = action.payload; //
}
}
else{
state.pages.push(action.payload);
}
state.pageStatus = "pageLoaded"
},

Resources