如何解决(React 和 Redux) 添加商品到购物车的问题
我正在学习一个教程,我们正在构建一个购物车,该教程仍未完成,但我想在继续教程之前解决这个问题。
问题是,当我尝试将任何商品添加到购物车时,购物车仍在提示我,我的购物车是空的。您可以在下面这张图片的 url 中注意到,我已将 ID 编号为 1 的商品添加到购物车中,并且数量 (qty) 也是 1。
但购物车在添加商品后不应响应此类消息。在代码所在的这个阶段,响应应该只是一个空白页面。
当我尝试对购物车项目进行控制台记录时,这还不起作用 - 它对我来说是一个空数组,但讲师正在接收有关产品的数据,这些数据已添加到购物车中。所以这可能是一个线索。
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,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))
},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;
解决方法
这里是错误:
const productId = match.params.div
应该是“id”而不是div
const productId = match.params.id
,
在cartReducers.js 中更新状态时使用state.cartItems
,在CartScreen.js 中使用const cart = useSelector(state => state.cart)
。
我看不到 index.js,但看起来您的州名可能不一致。建议:useSelector(state => state.cartItems)
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。