This is my CartScreen.js
import { useContext } from 'react';
import { Store } from '../Store';
import { Link } from 'react-router-dom';
import { Helmet } from 'react-helmet-async';
import MessageBox from '../components/MessageBox';
import ListGroup from 'react-bootstrap/ListGroup';
import Row from 'react-bootstrap/Row';
import Col from 'react-bootstrap/Col';
import Button from 'react-bootstrap/Button';
import Card from 'react-bootstrap/Card';
import axios from 'axios';
export default function CartScreen() {
const { state, dispatch: ctxDispatch } = useContext(Store);
const {
cart: { cartItems },
} = state;
const updateCartHandler = async (item,quantity) => {
const {data} = await axios.get(`/api/products/${item.name}`);
if(data.stock<quantity){
window.alert('Sorry. Product is out of sotck');
return;
}
ctxDispatch({
type: 'CART_ADD_ITEM',
payload: {...item,quantity}
})
};
const removeItemHandler= async(item) =>{
ctxDispatch({
type: 'CART_REMOVE_ITEM',
payload: {...item}
})
}
return (
<div>
<head>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css"
integrity="sha512-Fo3rlrZj/k7ujTnHg4CGR2D7kSs0v4LLanw2qksYuRlEzO+tcaEPQogQ0KaoGN26/zrn20ImR1DfuLWnOo7aBA=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
/>
</head>
<Helmet>
<title>Shopping Cart</title>
</Helmet>
<h1>Shopping Cart</h1>
<Row>
<Col md={8}>
{cartItems.length === 0 ? (
<MessageBox>
Cart is empty. <Link to="/">Go Shopping </Link>
</MessageBox>
) : (
<ListGroup>
{cartItems.map((item) => (
<ListGroup.Item key={item.name + item.selectedColor + item.selectedSize}>
<Row className="align-items-center">
<Col md={4}>
<img
src={item.image}
alt={item.name}
className="img-fluid rounded img-thumbnail"
></img>{' '}
<Link to={`/product/${item.name}`}>{item.name}</Link>
<div>Color: {item.selectedColor}</div>
<div>Size: {item.selectedSize}</div>
</Col>
<Col md={3}>
<Button variant="light" onClick={()=>updateCartHandler(item,item.quantity-1)}
disabled={item.quantity === 1}>
<i className="fas fa-minus-circle"></i>
</Button>{' '}
<span>{item.quantity}</span>{' '}
<Button variant="light"
onClick={()=>updateCartHandler(item,item.quantity+1)}
disabled={item.quantity === item.stock}>
<i className="fas fa-plus-circle"></i>
</Button>{' '}
</Col>
<Col md={3}>${(item.price+item.varyOfSize+item.varyOfColor) * item.quantity}</Col>
<Col md={2}>
<Button variant="light"
onClick={()=>removeItemHandler(item)}>
<i className="fas fa-trash"></i>
</Button>
</Col>
</Row>
</ListGroup.Item>
))}
</ListGroup>
)}
</Col>
<Col md={4}>
<Card>
<Card.Body>
<ListGroup variant="flush">
<h3>
Subtotal({cartItems.reduce((a, c) => a + Number(c.quantity), 0)} items) : $
{cartItems.reduce((a, c) => a + (c.price+c.varyOfSize+c.varyOfColor) * c.quantity, 0)}
</h3>
</ListGroup>
<ListGroup>
<div className="d-grid">
<Button
type="button"
variant="primary"
disabled={cartItems.length === 0}
>
Proceed to Checkout
</Button>
</div>
</ListGroup>
</Card.Body>
</Card>
</Col>
</Row>
</div>
);
}
This line is returning me a good result.
{cartItems.reduce((a, c) => a + Number(c.quantity), 0)}
but, the same line , which is in Apps.js, is giving me an outdated result,
import React from 'react';
import {BrowserRouter,Route, Routes,Link} from 'react-router-dom'
import HomeScreen from './screens/HomeScreen';
import ProductScreen from './screens/ProductScreen';
import CartScreen from './screens/CartScreen';
import Nav from 'react-bootstrap/Nav';
import Badge from 'react-bootstrap/Badge';
import {LinkContainer} from 'react-router-bootstrap';
import {useContext} from 'react';
import {Store} from './Store';
import {StoreProvider} from './Store';
function App() {
const {state} = useContext(Store);
const {cart} = state;
return (
<StoreProvider>
<BrowserRouter>
<div>
{/* <nav>*/}
<div className="menu-background">
<Link to="/" className="menu">amazonas</Link>
{/*<Link to="/" className="menu" >amazonas</Link> */}
<Link to="/cart" className="cart">
Cart
{
cart.cartItems.length>0 && (
<Badge pill bg="danger">
{cart.cartItems.reduce((a, c) => a + Number(c.quantity), 0)}
</Badge>
)}
</Link>
</div>
{/* <div className="logo-background">
<p className="logo">Menu</p>
</div> */}
{/* </nav>*/}
</div>
<Routes>
<Route path="/product/:_id" element={<ProductScreen />}></Route>
<Route path="/cart/:_id?" element={<CartScreen />}></Route>
<Route path="/" element={<HomeScreen />}></Route>
</Routes>
</BrowserRouter>
</StoreProvider>
)
}
export default App;
This is the line exactly
<Badge pill bg="danger">
{cart.cartItems.reduce((a, c) => a + Number(c.quantity), 0)}
</Badge>
I see that depends on const {cart}, and cart is equal to state. {sate }is equal to useContext(Store).
This is my Store.js
import { createContext, useReducer } from 'react';
export const Store = createContext();
const initialState = {
cart: {
cartItems: localStorage.getItem('cartItems')
? JSON.parse(localStorage.getItem('cartItems'))
: [],
},
};
function reducer(state, action) {
switch (action.type) {
case 'CART_ADD_ITEM': {
const newItem = action.payload;
const existItem = state.cart.cartItems.find(
(item) => item.name === newItem.name && item.selectedColor === newItem.selectedColor && item.selectedSize === newItem.selectedSize
);
const cartItems = existItem
? state.cart.cartItems.map((item) =>
item.name === newItem.name && item.selectedColor === newItem.selectedColor && item.selectedSize === newItem.selectedSize ? newItem : item
)
: [...state.cart.cartItems, newItem];
localStorage.setItem('cartItems', JSON.stringify(cartItems));
return { ...state, cart: { ...state.cart, cartItems } };
}
case 'CART_REMOVE_ITEM': {
const cartItems = state.cart.cartItems.filter(
(item) => item.name !== action.payload.name || item.selectedColor !== action.payload.selectedColor || item.selectedSize !== action.payload.selectedSize
);
localStorage.setItem('cartItems', JSON.stringify(cartItems));
return { ...state, cart: { ...state.cart, cartItems } };
}
default:
return state;
}
}
export function StoreProvider(props) {
const [state, dispatch] = useReducer(reducer, initialState);
const value = { state, dispatch };
return <Store.Provider value={value}>{props.children}</Store.Provider>;
}
Result
Do you understand what happening is?
When I add products to subtotal, it adds to subtotal correctly. My problem ins in the Cart.
