首页 > 解决方案 > redux 和反应不需要的效果

问题描述

大家好

  1. 我正在尝试使用 redux 制作购物车功能。

2.问题描述:

问题是,一旦我想从我的购物篮中取出不是最后一个产品。

Redux 确实从商店中删除了所需的产品,但在前端我仍然看到该产品并做出反应从列表中删除最后一个产品(我不想删除的那个)。

我必须转到另一个页面而不重新加载并返回购物篮才能看到对重置的反应

如果我从列表中删除最后一个产品,则删除工作正常。

我制作了一个由谷歌驱动器提供的视频链接:

https://drive.google.com/file/d/1miZA4B1Ay5OZZBGPj1bCcQHsGv21oVW_/view

这是我想要或期望拥有的 redux 效果(这是从购物车列表中删除最新产品的操作:

捕获-de-cran-2020-10-23-a-17-00-43.png

如果我的购物车中有多个产品,而我只想删除一个产品而不是最后一个(不需要的效果):

捕获-de-cran-2020-10-23-a-17-05-10.png

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>
            </>
        )
    }
}

如果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>
        </>
    )
}

标签: javascriptreactjsredux

解决方案


通过您自己的索引更改 React js 的默认索引来解决问题,对我来说,我使用从我的商店收到的索引来确保它们是唯一的


推荐阅读