How to take an array from store? - reactjs

I have a app that adds a product to the cart. I implement the application through the Redux Toolkit. When I click on the "Add to cart" button, all information about the product should be displayed in the cart.
Now the problem is that the added goods do not get into the array. An empty array is output to the console each time. How can you I this?
import { createSlice } from "#reduxjs/toolkit";
const initialState = {
productsArr: {
items: [],
},
};
const cartSlice = createSlice({
name: "cart",
initialState,
reducers: {
addItemToCart: (state, action) => {
state.productArr.items.concat([
{
id: action.payload.productId,
title: action.payload.productTitle,
},
]);
state.productArr.totalQuantity += 1;
},
},
});
// these exports should stay the way they are
export const { addItemToCart} = cartSlice.actions;
export default cartSlice.reducer;
const ProductItem = (props) => {
const { title, price, description, id } = props;
const productTitle = title;
const productId = id;
const dispatch = useDispatch();
const addToCartHandler = () => {
console.log(addItemToCart({ productId, productTitle }));
dispatch(addItemToCart({ productId, productTitle }));
};
return (
<li className={classes.item}>
<Card>
<header>
<h3>{title}</h3>
<div className={classes.price}>${price.toFixed(2)}</div>
</header>
<p>{description}</p>
<div className={classes.actions}>
<button onClick={addToCartHandler}>Add to Cart</button>
</div>
</Card>
</li>
);
};
const Cart = (props) => {
const cartItems = useSelector((state) => state.cart.productArr.items);
console.log(cartItems);
return(
<Card className={classes.cart}>
<h2>Your Shopping Cart</h2>
<ul>
{cartItems.map((cartItem) => (
<CartItem
item={{
title: cartItem.title,
// quantity: item.quantity,
// total: item.totalPrice,
// price: item.price,
key: cartItem.id,
}}
/>
))}
</ul>
</Card>
)
};

I think it should be
State.productArr.items.push(
{
id: action.payload.productId,
title: action.payload.productTitle,
});
Did you try with push method??

Related

How to use this to target a item in a mapped list in react

I am still pretty new and am doing a simple food ordering app in React. I have a file of dummy meals and am able to create a cart through user input, create a modal on the "Your Cart" button from the header, and map through the cart displaying as a list, but I am unable to figure out how to delete an item from the cart. I realize I need to target the id of the list item that the X is connected to, but for some reason I can't get the this command to work.
Is there something about the this command that I am not understanding when it comes to a mapped list item? So far I have both tried this through my CartModal component and the Home component, but both turn up undefined when using this and I throw an error when using e.target (enter different options like e.target.value, e.target.id, etc...), and have even tried working on an inline targeting (which is where the code below is at currently) but still comes up nothing.
I will add a couple dummy meals to this as well.
Thanks so much!
const initialState = 0;
const reducer = (state, action) => {
switch (action) {
case "increment":
return state + 1;
case "decrement":
return state - 1;
case "reset":
return initialState;
default:
return state;
}
};
export const CountContext = React.createContext();
const Home = (props) => {
const [cart, setCart] = useState([]);
const [count, dispatch] = useReducer(reducer, initialState);
const {isVisible, toggleModal} = useModal();
let totalPrice;
let cartCounter ;
const cartUpdaterHandler = (cartItem) =>{
setCart([...cart, cartItem]);
cartItem= cartItem;
}
useEffect(() => {
cartCounter = cart.length;
totalPrice = cart.reduce((acc, {price}) => parseFloat(acc) + parseFloat(price), 0).toFixed(2);
}, [cart])
const modalHandler = () => {
toggleModal(true)
}
const removeCI = () => {
console.log(cart)
}
return (
<CountContext.Provider
value={{ countState: count,
countDispatch: dispatch,
currentCart: cart
}}
className={classes.contextProvider}
>
{isVisible && (
<CartModal
overlayClassName="custom_overlay"
isVisible={isVisible}
hideModal={toggleModal}
currentCart={cart}
totalPrice={totalPrice}
remove={removeCI}
/>
)}
<Header cart={cart} cartCounter={cart} modal={modalHandler}/>
<Intro />
<MealForm onAdd={cartUpdaterHandler} />
{/* <Cart /> */}
{/* <CartModal isVisible={isVisible} hideModal={toggleModal} currentCart={cart} totalPrice={totalPrice}/> */}
</CountContext.Provider>
)
}
export default Home;
const CartModal = ({ isVisible, hideModal, currentCart, remove}) => {
// const checkKey = () => {
// console.log(cartItem.id)
// console.log(this.id)
// }
return isVisible
? createPortal(
<Card className={classes.modal}>
<div className={classes.modalBackground}>
<div className={classes.modalDiv}>
<div className={classes.modalHeader}>
<h5 className={classes.modalHeaderH5}>Your Cart</h5>
<button className={classes.modalHeaderX} onClick={hideModal}> X </button>
</div>
<div className={classes.modalBody}>
{currentCart.map((cartItem, i) => {
return<div key={Math.random()}>
<ul className={classes.cartModalItem} key={Math.random()}>
<div className={classes.cartModalItemInfo} >
<li className={classes.cartModalName}>{cartItem.name}</li>
<li className={classes.cartModalPrice}>{cartItem.price}</li>
<li className={classes.cartModalDesc}>{cartItem.description}</li>
</div>
//I am asking about the X below this.
<button className={classes.cartModalX} onClick={()=>{console.log(this)}}>X</button>
</ul>
</div>
})}
<h5 className={classes.modalTotal}>Total:{currentCart.reduce((acc, {price}) => parseFloat(acc) + parseFloat(price), 0).toFixed(2)} </h5>
</div>
<div className={classes.modalFooter}>
<button className={classes.closeModalButton} onClick={hideModal}> Close </button>
<button className={classes.orderModalButton}>Checkout</button>
</div>
</div>
</div>
</Card>,
document.body,
)
: null;
};
export default CartModal;
const AvalibleMeals = [
{
id: 'm1',
name: 'Sushi',
description: 'Finest fish and veggies',
price: 22.99,
},
{
id: 'm2',
name: 'Schnitzel',
description: 'A german specialty!',
price: 16.5,
},
{
id: 'm3',
name: 'Barbecue Burger',
description: 'American, raw, meaty',
price: 12.99,
},
{
id: 'm4',
name: 'Green Bowl',
description: 'Healthy...and green...',
price: 18.99,
},
];
export default AvalibleMeals;

Cannot set value from getStaticPaths even though it have value

I don't know why I can log value and i saw it have value, but when I set this value to ReactNode, it don't show anything. I just follow the docs of Nextjs.
What is my problem and how can I fix it?
my file name is [productId].tsx
My code
const productDetail : NextPage<Product>= (product) => {
console.log(product)
return (
<div>
<Navbar />
<div style={{ marginTop: 200 }}>
<div className="grid wide">
<div className="row">
<div className="col l-12 c-12 m-12">
<h1 className={styles.productName}>Name:{product.productName}</h1>
</div>
</div>
...
</div>
</div>
<Footer />
</div>
);
};
export const getStaticPaths: GetStaticPaths = async () => {
const { data } = await client.query<GetProductsQuery>({
query: GetProductsDocument,
variables: {
paginationOptions:{
skip:0
}
},
});
return {
paths: data.getProducts.products!.map((product) => ({
params: { productId: `${product.id}` },
})),
fallback: "blocking",
};
};
export const getStaticProps: GetStaticProps<
{ [key: string]: any },
{ productId: string }
> = async ({ params }) => {
const data = await client.query<GetProductQuery>({
query: GetProductDocument,
variables: { productId: params?.productId },
});
return {
props:{
product:data.data.getProduct.product
}
};
};
export default productDetail;
Have a nice day!
I don't know why but i fix my error by create a Props interface
interface Props{
product:Product
}
const productDetail: NextPage<Props> = ({product}) => {
...
}

Identify each item using keys from array data for add cart button. Reactjs. Redux

I have a display of products with each name, price and button(add to cart).
The problem is the first data(hoodie white) from my array of products (store component)is the only one that adds up. I can't find a way to identify each array of products when using my handler for dispatch.
Array products sample
const data = {
products:[
{
id: 1,
name: 'Hoodie white',
price: 19.99,
},
{
id: 2,
name: 'Hoodie black',
price: 19.99,
}
],
cart: [],
total: 0,
}
const ProductComponent=()=>{
const products= useSelector(state=>state.products);
const dispatch = useDispatch(0);
const [productid] = useState(0)
const purchaseHandler=(e)=>{
dispatch({ type: "PURCHASE", payLoad: products[productid] });
}
return(
products.map((product, i)=>{
return(
<>
<img src={products.image} className="product-image" alt={product.name} />
<div className='namebtn'>
<h3 className='product-name-text' key={i}>{product.name}</h3>
<div key={i}>${product.price}</div>
<button onClick={purchaseHandler} className="addToCart">Add to Cart</button>
</div>
</>
)})
)
}
Why not pass the product.id to purchaseHandler function
const ProductComponent = () => {
const products = useSelector((state) => state.products);
const dispatch = useDispatch(0);
const purchaseHandler = (e, productid) => {
dispatch({ type: 'PURCHASE', payLoad: products[productid] });
};
return products.map((product, i) => {
return (
<>
<img src={products.image} className="product-image" alt={product.name} />
<div className="namebtn">
<h3 className="product-name-text" key={i}>
{product.name}
</h3>
<div key={i}>${product.price}</div>
<button onClick={(e) => purchaseHandler(e, product.id)} className="addToCart">
Add to Cart
</button>
</div>
</>
);
});
};

I cannot get index to each dispatch working

How to get the dispatch to recognize each product when the button is clicked?
When the HTML is mapped through the examples array, there is an index given. But when I click the button to addToCart, the elements of objects of array, it shows undefined
{type: "ADD_TO_CART", item: {…}}
item: {id: undefined, name: undefined, price: undefined, desc: undefined, type: undefined, …}
type: "ADD_TO_CART"
This is Menu.js
import React, { useState } from 'react';
import examples from './examples';
import './Menu.css';
import { useStateValue } from './StateProvider';
const Menu = ({ id, name, imgUrl, desc, price, type }) => {
const [dishes, setDishes] = useState(examples);
const [, dispatch] = useStateValue();
const addToCart = () => {
// add item to basket
dispatch({
type: 'ADD_TO_CART',
item: {
id,
name,
price,
desc,
type,
imgUrl,
},
});
};
return (
<div className='menu'>
<h1>Menu</h1>
<div className='menu__starters'>
<h1>Starters</h1>
{dishes.map((dish, index) => (
<div className='menu__column'>
<div className='menu__row'>
<div className='menu__card' key={index}>
<div className='menu__img'>
<img src={dish.imgUrl} alt='img' />
</div>
<div className='menu__desc'>
<div className='menu__name'>
<h2>{dish.name}</h2>
</div>
<div className='menu__description'>
<p>{dish.desc}</p>
</div>
<div className='menu__credentials'>
<div className='menu__price'>
<h5>Damage- ${dish.price}</h5>
</div>
<div className='menu__button'>
<button onClick={addToCart} key={index}>
Add to Cart ->
</button>
</div>
</div>
</div>
</div>
</div>
</div>
))}
</div>`
An array of objects is in another file examples.js which is exported.
This is reducer.js
export const initialState = {
cart: [],
};
function reducer(state, action) {
console.log(action);
switch (action.type) {
case 'ADD_TO_CART':
// logic for adding item to cart
return { state };
break;
case 'REMOVE_FROM_CART':
//logic for removing item from cart
return { state };
break;
default:
return state;
}
}
export default reducer;`
Blockquote
It's undefined because those variables are not defined in addToCart scope, you haven't passed any data to it.
You have to pass the dish into addToCart
<button onClick={()=>addToCart(dish)} ...>
And
const addToCart = ({ id, name, imgUrl, desc, price, type }) => {...}

Filter by category React Redux

I have a data which I receive from Redux Store, also I have categories by which I need to filter data by clicking on appropriate category button. How can I implement filter using Redux?
items from database has output like this:
items = [{
id: 0
name: "example1"
price: 15
category: 0
},
{
id: 1
name: "example2"
price: 15
category: 1
}
]
categories has output:
categories = ["one", "two"]
This is my Component:
export default function Home() {
const itemData = useSelector((state) => state.main.items);
const loader = useSelector((state) => state.load.loading);
const [activeCategory, setActiveCategory] = useState(null);
const dispatch = useDispatch();
useEffect(() => {
dispatch(fetchItems());
}, [dispatch]);
if (loader) {
return <Spinner />;
}
return (
<div className="container">
<div className="content__top">
<div className="categories">
<ul>
<li
className={activeCategory === null ? 'active' : ''}
onClick={() => setActiveCategory(null)}>
All
</li>
{categories &&
categories.map((category, index) => (
<li
key={index}
className={activeCategory === index ? 'active' : ''}
onMouseDown={() => dispatch(filterByCategory(itemData, category))}
onClick={() => setActiveCategory(index)}>
{category}
</li>
))}
</ul>
</div>
</div>
<h2 className="content__title">Items</h2>
<div className="content__items">
{itemData && itemData.map((item) => <Content key={item._id} {...item} />)}
</div>
</div>
);
}
This is my Action:
export const FETCH_ITEMS = 'FETCH_ITEMS';
export const FILTER_BY_CATEGORY = 'FILTER_BY_CATEGORY';
export const fetchItems = () => {
return (dispatch) => {
dispatch(showLoader());
axios.get('http://localhost:4000/').then((response) => {
const items = response.data;
dispatch({
type: FETCH_ITEMS,
payload: items,
});
dispatch(hideLoader());
});
};
};
export const filterByCategory = (items, category) => {
return {
type: FILTER_BY_CATEGORY,
category,
// some kind of filter code
};
};
And Reducer
const initialState = {
items: [],
};
export const fetchReducer = (state = initialState, action) => {
switch (action.type) {
case actions.FETCH_ITEMS:
return { ...state, items: action.payload };
case actions.FILTER_BY_CATEGORY:
return { ...state, filtered: action.category, category }; // Not sure about it
default:
return state;
}
};
Here is a working example using selectors:
const { Provider, useSelector } = ReactRedux;
const { createStore, applyMiddleware, compose } = Redux;
const { createSelector } = Reselect;
const initialState = {
items: [
{
id: 0,
name: 'example1',
price: 15,
category: 0,
},
{
id: 1,
name: 'example2',
price: 15,
category: 1,
},
{
id: 2,
name: 'example3',
price: 88,
category: 1,
},
],
};
const reducer = (state) => state;
//selectors
const selectItems = (state) => state.items;
const selectCategories = createSelector(
[selectItems],
(items) => [
...new Set(
items.map(({ category }) => category).sort()
),
]
);
const createSelectFilteredItems = (filterFunction) =>
createSelector([selectItems], (items) =>
items.filter(filterFunction)
);
//creating store with redux dev tools
const composeEnhancers =
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(
reducer,
initialState,
composeEnhancers(
applyMiddleware(() => (next) => (action) =>
next(action)
)
)
);
const App = () => {
const categories = useSelector(selectCategories);
const [
selectedCategory,
setSelectedCategory,
] = React.useState();
const selectFilteredItems = React.useMemo(
() =>
createSelectFilteredItems(({ category }) =>
selectedCategory === undefined
? true
: category === selectedCategory
),
[selectedCategory]
);
const filteredItems = useSelector(selectFilteredItems);
return (
<div>
<label>
select category
<select
value={selectedCategory}
onChange={({ target: { value } }) =>
setSelectedCategory(
value === 'all' ? undefined : Number(value)
)
}
>
<option value="all">all</option>
{categories.map((category) => (
<option key={category} value={category}>
{category}
</option>
))}
</select>
</label>
<ul>
{filteredItems.map((item) => (
<li key={item.id}>{JSON.stringify(item)}</li>
))}
</ul>
</div>
);
};
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.5/redux.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/7.2.0/react-redux.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/reselect/4.0.0/reselect.min.js"></script>
<div id="root"></div>

Resources