Reputation: 59
I am following a tutorial, where we are building a shopping cart, which is still unfinished, but I would like to solve this problem before continuing in the tutorial.
The thing is, that when I try to add any item to the cart, the cart is still saying me, that my shopping cart is empty. You can notice in the url of this picture below, that I have added the item with id number 1 to the shopping cart and quantity (qty) is also 1.
But the shopping cart should not respond this kind of message after adding an item into it. At this stage, in which the code is, the response should be just a blank page.
This didn´t work yet when I was trying to console.log the cartItems - it was an empty array for me, but the instructor was receiving the data about the products, which were added to cart. So that might be a clue.
Please take a look at the following files and let me know, if You will be able to see any hint or a solution.
CartScreen.js -
import React, {useEffect} from 'react'
import { Link } from 'react-router-dom'
import { useDispatch, useSelector } from 'react-redux'
import { Row, Col, ListGroup, Image, Form, Button, Card } from 'react-bootstrap'
import Message from '../components/Message'
import { addToCart } from '../actions/cartActions'
function CartScreen({ match, location, history }) {
const productId = match.params.div
const qty = location.search ? Number(location.search.split('=')[1]) : 1
const dispatch = useDispatch()
const cart = useSelector(state => state.cart)
const { cartItems } = cart
useEffect(() =>{
if(productId){
dispatch(addToCart(productId, qty))
}
}, [dispatch, productId, qty])
return (
<Row>
<Col md={8}>
<h1>Shopping Cart</h1>
{cartItems.length === 0 ? (
<Message variant='info'>
Your cart is empty <Link to='/'>Go Back</Link>
</Message>
) : (
<listGroup variant='flush'>
</listGroup>
)}
</Col>
<Col md={4}>
</Col>
</Row>
)
}
export default CartScreen
cartActions.js -
import axios from 'axios'
import { CART_ADD_ITEM } from '../constants/cartConstants'
export const addToCart = (id, qty) => async (dispatch, getState) => {
const { data } = await axios.get(`/api/products/${id}`)
dispatch({
type:CART_ADD_ITEM,
payload:{
product:data._id,
name:data.name,
image:data.image,
price:data.price,
countInStock:data.countInStock,
qty
}
})
localStorage.setItem('cartItems', JSON.stringify(getState().cart.cartItems))
}
cartReducers.js -
import { CART_ADD_ITEM } from '../constants/cartConstants'
export const cartReducer = (state={cartItems:[] }, action) => {
switch (action.type) {
case CART_ADD_ITEM:
const item = action.payload
const existItem = state.cartItems.find(x => x.product === item.product)
if(existItem){
return{
...state,
cartItems: state.cartItems.map(x =>
x.product === existItem.product ? item : x)
}
}else{
return{
...state,
cartItems:[...state.cartItems, item]
}
}
default:
return state
}
}
cartConstants.js -
export const CART_ADD_ITEM = 'CART_ADD_ITEM'
export const CART_REMOVE_ITEM = 'CART_REMOVE_ITEM'
store.js -
import { createStore, combineReducers, applyMiddleware } from 'redux'
import thunk from 'redux-thunk'
import { composeWithDevTools } from 'redux-devtools-extension'
import { productListReducer, productDetailsReducer } from './reducers/productReducers'
import { cartReducer } from './reducers/cartReducers'
const reducer = combineReducers({
productList:productListReducer,
productDetails:productDetailsReducer,
cart: cartReducer,
})
const cartItemsFromStorage = localStorage.getItem('cartItems') ?
JSON.parse(localStorage.getItem('cartItems')) : []
const initialState = {
cart: { cartItems: cartItemsFromStorage }
}
const middleware = [thunk]
const store = createStore(reducer, initialState,
composeWithDevTools(applyMiddleware(...middleware)))
export default store
ProductScreen.js -
import React, { useState, useEffect } from "react";
import { useDispatch, useSelector } from 'react-redux'
import { Link } from "react-router-dom";
import { Row, Col, Image, ListGroup, Button, Card, Form } from "react-bootstrap";
import Rating from "../components/Rating";
import Loader from "../components/Loader";
import Message from "../components/Message";
import { listProductDetails } from '../actions/productActions'
function ProductScreen({ match, history }) {
const[qty, setQty] = useState(1)
const dispatch = useDispatch()
const productDetails = useSelector(state => state.productDetails)
const { loading, error, product } = productDetails
useEffect(() => {
dispatch(listProductDetails(match.params.id))
},[dispatch, match])
const addToCartHandler = () => {
history.push(`/cart/${match.params.id}?qty=${qty}`)
}
return (
<div>
<Link to="/" className="btn btn-light my-3">
Go Back
</Link>
{loading ?
<Loader/>
: error
? <Message variant='danger'>{error}</Message>
:(
<Row>
<Col md={6}>
<Image src={product.image} alt={product.name} fluid />
</Col>
<Col md={3}>
<ListGroup variant="flush">
<ListGroup.Item>
<h3>{product.name}</h3>
</ListGroup.Item>
<ListGroup.Item>
<Rating
value={product.rating}
text={`${product.numReviews} reviews`}
color={"#f8e825"}
/>
</ListGroup.Item>
<ListGroup.Item>Price: ${product.price}</ListGroup.Item>
<ListGroup.Item>Description: {product.description}</ListGroup.Item>
</ListGroup>
</Col>
<Col md={3}>
<Card>
<ListGroup variant="flush">
<ListGroup.Item>
<Row>
<Col>Price:</Col>
<Col>
<strong>${product.price}</strong>
</Col>
</Row>
</ListGroup.Item>
<ListGroup.Item>
<Row>
<Col>Status:</Col>
<Col>
{product.countInStock > 0 ? "In Stock" : "Out of Stock"}
</Col>
</Row>
</ListGroup.Item>
{product.countInStock > 0 && (
<ListGroup.Item>
<Row>
<Col>Qty</Col>
<Col xs='auto' className='my-1'>
<Form.Control
as="select"
value={qty}
onChange={(e) => setQty(e.target.value)}
>
{
[...Array(product.countInStock).keys()].map((x) => (
<option key={x + 1} value={x + 1}>
{x + 1}
</option>
))
}
</Form.Control>
</Col>
</Row>
</ListGroup.Item>
)}
<ListGroup.Item>
<Button
onClick={addToCartHandler}
className="btn-block"
disabled={product.countInStock == 0}
type="button"
>
Add to Cart
</Button>
</ListGroup.Item>
</ListGroup>
</Card>
</Col>
</Row>
)
}
</div>
);
}
export default ProductScreen;
Upvotes: 1
Views: 2409
Reputation: 49182
here is the error :
const productId = match.params.div
it should be "id" not div
const productId = match.params.id
Upvotes: 1
Reputation: 405
In cartReducers.js you are using state.cartItems
when updating the state and in the CartScreen.js you are using const cart = useSelector(state => state.cart)
.
I can't see the index.js but it looks like you may have an inconsistency in your state names. Suggestion: useSelector(state => state.cartItems)
Upvotes: 0