大家好????
- 我正在尝试使用 redux 来制作购物车功能。
2.问题描述:
问题是,一旦我想从我的购物篮中删除不是最后一个的产品。
Redux 确实从商店中删除了所需的产品,但在前端我仍然可以看到该产品,并且 React 会从列表中删除最后一个产品(我不想删除的产品)。
我必须转到另一个页面而不重新加载并返回购物篮才能看到重置的反应
如果我从列表中删除最后一个产品,则删除会按预期进行。
我制作了一个由谷歌驱动器提供的视频链接:
https://drive.google.com/file/d/1miZA4B1Ay5OZZBGPj1bCcQHsGv21oVW_/view https://drive.google.com/file/d/1miZA4B1Ay5OZZBGPj1bCcQHsGv21oVW_/view
这是我想要或预期具有的 redux 效果(这是从购物车列表中删除最新产品的操作:
如果我的购物车中有多个产品,并且我只想删除一个产品而不是最后一个产品(不必要的效果):
ADD_TO_CART_ACTIONdispatch
store.dispatch({
type: ADD_PRODUCT_TO_CART_ACTION,
payload: {
data: {
productID: data.product.id,
attributeID: RadioState,
price: data.price,
quantity: 1
}
}
})
这是我的购物车减速器:
export function CartReducer(state = [], action){
const cart = [...state]
switch (action.type){
case 'ADD_PRODUCT_TO_CART_ACTION':
return [...state, {...action.payload.data}];
case 'UPDATE_QUANTITY_FROM_CART_ACTION':
return cart.map(product => {
if (product.attributeID === action.payload.attributeID){
product.quantity++
return {...product}
} else {
return product
}
})
case 'REMOVE_QUANTITY_FROM_CART_ACTION':
return cart.map(product => {
if (product.attributeID === action.payload.attributeID){
product.quantity--
return {...product}
} else {
return product
}
})
case 'TRASH_PRODUCT_FROM_CART_ACTION':
return cart.filter(product => product.attributeID !== action.payload)
default:
return state;
}
}
这是首先从 redux 连接的购物车组件:
export function Cart (props)
{
const [productCount, setProductCount] = useState(0)
useEffect(() => {
setProductCount(props.count)
}, [])
if (props.cart.length === 0){
return <div className="home"><p className={'text-center text-green-500'}>Add product to cart.</p></div>
}
return (
<React.Fragment className="home">
<Grid container spacing={3}>
{props.cart.map((item, index) => {
return (
<Grid item xs={6}>
<ProductCartDetails productCount={productCount} key={index} attributes={item}/>
</Grid>
)
})}
</Grid>
</React.Fragment>
)
}
export const CartStore = connect(
(state) => ({
cart: cartSelectors(state),
count: cartCount(state)
})
)(Cart)
这是ProductCartDetails(产品的卡片,这里的操作是调度的)
export default function ProductCartDetails (props){
const [productCount, setProductCount] = useState(0)
const [product, setProduct] = useState([])
const [requestReady, setRequestReady] = useState(false)
useEffect(() => {
axios.get(`product/${props.attributes.productID}`)
.then(({data}) => {
setProduct(data)
setRequestReady(! requestReady)
})
.catch((err) => {
console.log(err)
})
}, [props.productCount])
useEffect(() => {
setProductCount(props.productCount)
}, [props.productCount])
const useStyles = makeStyles((theme) => ({
root: {
display: 'flex',
width: "100%",
marginTop: 4,
backgroundColor: "#faf7f7",
boxSizing: 'border-box',
},
details: {
display: 'flex',
flexDirection: 'column',
},
content: {
flex: '1',
},
cover: {
width: 151,
height: '100%'
},
}));
const onClickAddMoreQuantity = () => {
let cart = [...store.getState()]
let updatedQuantity = false;
cart.map(product => {
if (product.attributeID === props.attributes.attributeID){
store.dispatch(
{
type: UPDATE_QUANTITY_FROM_CART_ACTION,
payload: {
attributeID: props.attributes.attributeID
}
}
)
updatedQuantity = true
}
})
if (updatedQuantity === false){
swal({
icon: 'error',
title: 'Cart',
text: 'Product quantity cannot be bigger than the product stock.',
})
}
}
const onClickRemoveQuantityFromCart = () => {
let cart = [...store.getState()]
let updatedQuantity = false;
cart.map(product => {
if (product.attributeID === props.attributes.attributeID){
store.dispatch(
{
type: REMOVE_QUANTITY_FROM_CART_ACTION,
payload: {
attributeID: props.attributes.attributeID
}
}
)
updatedQuantity = true
}
})
if (updatedQuantity === false){
swal({
icon: 'error',
title: 'Cart',
text: 'Product quantity has not been removed.',
})
}
}
const onClickTrashProductFromCart = () => {
let cart = [...store.getState()]
let updatedQuantity = false;
cart.map(product => {
if (product.attributeID === props.attributes.attributeID){
store.dispatch(
{
type: TRASH_PRODUCT_FROM_CART_ACTION,
payload: props.attributes.attributeID
}
)
updatedQuantity = true
}
})
if (updatedQuantity === false){
swal({
icon: 'error',
title: 'Cart',
text: 'Product has not been removed.',
})
}
}
const classes = useStyles();
if (productCount !== 0){
return (
<>
<Card className={classes.root}>
<Link to={requestReady ? `/details/${product.slug}` : null}>
<img
className={classes.cover}
src={requestReady ? axios.defaults.baseURL+product.image[0].url+"?h=600" : null}
alt="image cover product cart"
/>
</Link>
<div className={classes.details}>
<CardContent className={classes.content}>
<Typography className="text-center text-gray-700" component="h6" variant="h6">
{requestReady ? product.name : null}
</Typography>
<p className="text-center text-gray-600">
Details Of Product
</p>
<div>
<Typography variant="subtitle1" color="textSecondary">
Category: {requestReady ? product.category.label : null}
</Typography>
<Typography variant="subtitle1" color="textSecondary">
<ProductCartAttributeDetails attributes={props.attributes} />
</Typography>
</div>
</CardContent>
<CardActions>
<button id={requestReady ? product.id : null} onClick={onClickAddMoreQuantity}>
<Add height={10} />Add quantity
</button>
<button>
<Delete height={10} onClick={onClickTrashProductFromCart} />Trash
</button>
<button onClick={onClickRemoveQuantityFromCart}>
<Remove height={10} />Remove quantity
</button>
</CardActions>
</div>
</Card>
</>
)
} else {
return (
<>
<Card className={classes.root}>
<Link to={requestReady ? `/details/${product.slug}` : null}>
<img
className={classes.cover}
src={requestReady ? axios.defaults.baseURL+product.image[0].url+"?h=600" : null}
alt="image cover product cart"
/>
</Link>
<div className={classes.details}>
<CardContent className={classes.content}>
<Typography className="text-center text-gray-700" component="h6" variant="h6">
{requestReady ? product.name : null}
</Typography>
<p className="text-center text-gray-600">
Details Of Product
</p>
<div>
<Typography variant="subtitle1" color="textSecondary">
Category: {requestReady ? product.category.label : null}
</Typography>
<Typography variant="subtitle1" color="textSecondary">
<ProductCartAttributeDetails attributes={props.attributes} />
</Typography>
</div>
</CardContent>
<CardActions>
<button id={requestReady ? product.id : null} onClick={onClickAddMoreQuantity}>
<Add height={10} />Add quantity
</button>
<button>
<Delete height={10} onClick={onClickTrashProductFromCart} />Trash
</button>
<button onClick={onClickRemoveQuantityFromCart}>
<Remove height={10} />Remove quantity
</button>
</CardActions>
</div>
</Card>
</>
)
}
}
And the ProductCartAttributeDetails
如果需要的话
export default function ProductCartAttributeDetails({attributes}){
const [attribute, setAttribute] = useState([])
const [requestReady, setRequestReady] = useState(false)
useEffect(() => {
axios.get(`attributes/${attributes.attributeID}`)
.then(({data}) => {
setAttribute(data)
setRequestReady(! requestReady)
})
.catch((err) => {
console.log(err)
})
}, [])
return (
<>
<Typography variant="subtitle1" color="textSecondary">
<p><span className="capitalize">{requestReady ? attribute.attribute : null}</span> : {requestReady ? attribute.value : null}</p>
</Typography>
<Typography variant="subtitle1" color="textSecondary">
<p>Quantity: {requestReady ? attributes.quantity : null}</p>
</Typography>
<Typography variant="subtitle1" color="textSecondary">
<p>Total Price: {requestReady ? attribute.price * attributes.quantity : null}</p>
</Typography>
</>
)
}