redux and react unwanted effect

元气小坏坏 提交于 2020-12-06 08:26:09

问题


Hello everyone 👋

  1. I'm trying to make a cart functionality with redux.

2.Description of problem:

The problem is that as soon as I want to remove a product that is not the last from my basket.

Redux does delete the desired product from the store, but at the frontend I still see the product and react deletes the last product from the list (the one I didn't want to delete).

I have to go to another page without reloading and returning to the basket to see react to reset

If I remove the last product from the list the removal works as it should.

I have made a video link that are served by google drive:

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

Here is the redux effect I want or expected to have ( this is the action of removing the latest product from cart list :

If I have several products in my cart and I just want to delete a product without it being the last ( unwanted effect ):

The ADD_TO_CART_ACTION dispatch

store.dispatch({
   type: ADD_PRODUCT_TO_CART_ACTION,
   payload: {
        data: {
          productID: data.product.id,
          attributeID: RadioState,
          price: data.price,
          quantity: 1
   }
 }
})

this is my cart reducer:

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;
    }
}

Here is the cart component who them is connected from redux first:

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)

This is ProductCartDetails ( The card of the product, and here who action are dispatch )

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 if needed

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

回答1:


Problem was fixed by changing the default index of react js by your own index, for me i have use the index that i receive from my store to be sure them is unique



来源:https://stackoverflow.com/questions/64502691/redux-and-react-unwanted-effect

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!