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?
Related
I need to make a variable in ProfilePic.js let pageId = 1 which store a number and it will increase +1 on each time ProfilePic.js renders and need to pass the same updated value to ProfilePicSlice.js so that incremented value can be pass on fetch(${IMAGE_API}${otherTopic}"&page=2"${ACCESS_KEY}).
Exceptions: Each time ProfilePic.js renders then images need to fetch from page 2 then page 3 then page 4.
Please help.
ProfilePic.js
import React, { useEffect, useState } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { getImages, selectedImage, removeImage } from './ProfilePicSlice';
const ProfilePic = () => {
const dispatch = useDispatch();
const { images, loading } = useSelector((state) => state.imageList);
const users = useSelector(store => store.users);
const navigate = useNavigate();
useEffect(() => {
if ((localStorage.getItem('topic') !== users.slice(-1)[0]?.topic && localStorage.getItem('topic') !== users.slice(-1)[0]?.otherTopic) || images.length < 1) {
dispatch(getImages(pageId));
}
}, [images])
return (
<> displaying images using map </>
)
};
export default ProfilePic;
ProfilePicSlice.js
import { createSlice, createAsyncThunk } from '#reduxjs/toolkit'
import { IMAGE_API, ACCESS_KEY } from "../../app/utils/constant";
export const getImages = createAsyncThunk('imageList/images',
(async, { getState }) => {
const store = getState();
const topic = store.users.slice(-1)[0].topic;
const otherTopic = store.users.slice(-1)[0].otherTopic;
let page = "&page=" = **2(this number should comes from profilepic.js)**
if (topic === 'Other') {
localStorage.setItem('topic', otherTopic)
return fetch(`${IMAGE_API}${otherTopic}"&page=2"${ACCESS_KEY}`)
.then((res) => res.json());
} else {
localStorage.setItem('topic', topic)
return fetch(`${IMAGE_API}${topic}"&page=2"${ACCESS_KEY}`)
.then((res) => res.json());
}
});
const ProfilePicSlice = createSlice({
name: 'imageList',
initialState: {
images: [],
selectedImage: [],
loading: false,
},
extraReducers: (builder) => {
builder.addCase(getImages.pending, (state, action) => {
state.loading = true;
})
builder.addCase(getImages.fulfilled, (state, action) => {
state.loading = false;
state.images = [];
state.images.push(...action.payload.results.map(img => img.urls.small));
})
builder.addCase(getImages.rejected, (state) => {
state.loading = true;
})
},
});
export const { selectedImage, removeImage } = ProfilePicSlice.actions
export default ProfilePicSlice.reducer
I am trying to make a system like shopping cart with redux and react. The products are stored in a redux slice array as a whole object. The product object goes like this:
This is my code for my checkbox input
const products = useSelector((state) => state.prodSlice.value)
const handleChange = (event) => {
const button = event.target
const isActive = button.checked
const itemName = event.currentTarget.id
const items = products.items
const itemsArr = {}
items.forEach((items) => {
if (items.productName === itemName) {
itemsArr['productName'] = items.productName
itemsArr['total'] = items.total
itemsArr['quantity'] = items.quantity
if (isActive) {
dispatch(checkout({products: itemsArr}))
} else {
dispatch(removeItem({products: itemsArr}))
}
}
})
}
When adding products to the array, there is no problem,
However, when I uncheck an item, and get the value of array it returns just an empty array instead of removing just 1 item.
I just want to delete that one item from the array, here is my redux slice code
import { createSlice } from "#reduxjs/toolkit";
const initialState = {
value: {
products: [],
}
}
export const checkOut = createSlice({
name: "checkout",
initialState,
reducers: {
checkout: (state, action) => {
state.value.products.push(action.payload)
},
removeItem: (state, action) => {
state.value.products = state.value.products.filter((products) => products.produdctName !== action.payload.productName)
}
}
})
export const { checkout, removeItem } = checkOut.actions
export default checkOut.reducer
I hope someone can help me pls
your removeItem reducer should simply return the filtered array
removeItem: (state, action) => {
return state.value.products.filter((products) => products.productName !== action.payload.productName)
}
Hi folks I am new to React just learning reduxjs/toolkit for application state management. I have created simple application for handling posts. Currently what I am doing is loading list of posts using async Thunk called fetchPosts. My async thunk is being called twice on application load and I have literally no idea what is making to do so. I am using react version 18.2.0 and here is my post slice.
import { createAsyncThunk, createSlice, nanoid } from "#reduxjs/toolkit";
import {sub} from 'date-fns';
import axios from 'axios';
const POST_URL = 'http://jsonplaceholder.typicode.com/posts';
const initialState = {
posts : [],
status : 'idle',
error : null
};
export const fetchPosts = createAsyncThunk('posts/fetchPosts', async () => {
const response = await axios.get(POST_URL);
return response.data;
});
const postsSlice = createSlice({
name: 'posts',
initialState,
reducers:{
postAdded: {
reducer(state, action) {
state.posts.push(action.payload);
},
prepare(title,content, userId){
return {
payload:{
id: nanoid(),
title,
content,
userId,
date: new Date().toISOString(),
reactions: {
thumbsUp: 0,
wow:0,
heart:0,
rocket:0,
coffee:0
}
}
}
}
},
reactionAdded(state, action) {
const {postId, reaction} = action.payload;
const existingPost = state.posts.find(post => post.id === postId);
if (existingPost) {
existingPost.reactions[reaction]++;
}
}
},
extraReducers(builder){
builder.addCase(fetchPosts.pending, (state, action) => {
state.status = 'loading';
})
.addCase(fetchPosts.fulfilled, (state, action) => {
state.status = 'succeeded';
let min = 1;
const loadedPosts = action.payload.map(post =>
{
post.date = sub(new Date(), {minutes: min++}).toISOString();
post.reactions = {
thumbsUp: 0,
wow: 0,
heart:0,
rocket:0,
coffee:0
}
return post;
});
state.posts = loadedPosts;
})
.addCase(fetchPosts.rejected, (state, action) => {
state.status = 'failed';
state.error = action.error.message
})
}
});
export const {postAdded,reactionAdded} = postsSlice.actions;
export const selectAllPosts = (state) => state.posts.posts;
export const getPostsStatus = (state) => state.posts.status;
export const getPostsError = (state) => state.posts.error;
export default postsSlice.reducer;
And here is my Post list component.
import React from 'react'
import { useSelector, useDispatch } from 'react-redux';
import { selectAllPosts, getPostsError, getPostsStatus, fetchPosts } from './postsSlice';
import { useEffect } from 'react';
import PostExcerpt from './PostExcerpt';
const PostsList = () => {
const dispatch = useDispatch();
const posts = useSelector(selectAllPosts);
const postStatus = useSelector(getPostsStatus);
const postError = useSelector(getPostsError);
useEffect(() => {
console.log('post status: ', postStatus);
if(postStatus === 'idle')
{
dispatch(fetchPosts());
}
},[postStatus])
let content;
if(postStatus === 'loading'){
console.log('loading');
content = <p>"Loading..."</p>
}
else if(postStatus === 'succeeded'){
console.log('succeded');
const orderedPosts = posts.slice().sort((a,b) => b.date.localeCompare(a.date));
content = orderedPosts.map(post => <PostExcerpt key={post.id} post={post}/>);
}
else if (postStatus === 'failed'){
content = <p>{postError}</p>;
}
return (
<section>
<h2>Posts</h2>
{content}
</section>
);
}
export default PostsList
So this was happening due to the mount -> unmount -> remount behaviour of component implemented in react version 18 useEffect.
I have an api which gives me the result, and I can see the data in my console, but I'm not able to get it in useSelector.
import { createAsyncThunk, createSlice } from "#reduxjs/toolkit";
import axios from "axios";
import { useNavigate } from "react-router-dom";
const initialState = {
value: [],
status: 'idle',
};
export const fetchEmployeesThunk = createAsyncThunk(
'employeelist/fetchEmployeesThunk',
async () => {
const res = await axios.get('https://localhost:7168/Employee/GetEmployeeList').then(
(result) => result.data
)
return res;
})
export const EmployeeListSlice = createSlice({
name: "employeelist",
initialState: initialState,
reducers: {
initialFetch: (state, action) => {
state.value = action.payload;
},
updateEmployeeList: (state, action) => {
state.value = action.payload;
},
},
extraReducers: (builder) => {
builder
.addCase(fetchEmployeesThunk.pending, (state, action) => {
state.status = 'idle';
state.value = [];
})
.addCase(fetchEmployeesThunk.fulfilled, (state, action) => {
console.log(action.payload);
state.value = action.payload;
state.status = 'finished';
})
},
});
export const getEmployeeListData = (state) => state.employeelist.value;
export const { updateEmployeeList, initialFetch } = EmployeeListSlice.actions;
export default EmployeeListSlice.reducer;
export function fetchEmployees() {
return async (dispatch) => {
const res = await axios.get('https://localhost:7168/Employee/GetEmployeeList').then(
(result) => result.data
)
dispatch(updateEmployeeList(res));
}
}
as you can see I tried using both thunk and creating a function and dispatching the data internally to an action, i was able to update the state but i'm not able to get the value through selector, I have a table which takes an array
export default function HomePage() {
const dispatch = useDispatch();
const [tempRows, setTempRows] = useState(useSelector((state) => state.employeelist.value));
const [rows, setTableRows] = useState(useSelector((state) => state.employeelist.value));
useEffect(() => {
//dispatch(fetchEmployees());
dispatch(fetchEmployeesThunk());
}, rows);
}
This is giving me empty array, but lets say if I change something then reload like a hot reload it returns the data now, any help would be deeply appreciated
Please do
const rows = useSelector((state) => state.employeelist.value)
and not
const [rows, setTableRows] = useState(useSelector((state) => state.employeelist.value));
The latter means "use local state that is once initialized from the Redux store". It will only change if setTableRows is called, not if the Redux store changes.
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));
}
},