简体   繁体   中英

Why my functional component doesn't re-render when change state? (react)

I'm stuck in project because my functional component do not re-render when I update this state.

const OneProduct = (props) => {
return (
<div className='productincart'>
    <div className='name'>{props.name}</div> 
    <div className='price'>Price: {props.price}</div>
    <div className='quantity'>{props.quantity}</div>
</div>)
}

const InsideCart = (props) => {
    const cartTemporary = props.sendCart
    const [cart, setCart] = useState([])

    useEffect(() => {
        setCart(cartTemporary)
        }, [cartTemporary])

    const showCart = () => {
        console.log(cart)
    }

    return (

        <div className='insidecart'>
            {cart.map(product => <OneProduct name={product.name} price= 
            {product.price} quantity={product.quantity} key={uniqid()} />)}
            <button onClick={showCart}>SHOW CART</button>
        </div>
    )
    }

In code above, I putting products from shop to the cart , next I want to display it on the screen. When I'm putting new item to the cart (new object in cart array), everything works fine. When I'm only update quantity of object already exist in cart array, nothing happens. After quantity updating, cart is updated with new value, but it doesn't causing re-render of component.

That is problem to solve, how to make component re-render after quantity value update.

Below format of objects which I add to cart , also added mechanism of adding and increasing quantity.

const Products = (props) => {
    const initialProducts = [
        { id: 0, name: "Fish - Betta splendens - Plakat Koi - Siamese fighting fish", image: image0, price: 23.17, quantity: 1 },
        { id: 1, name: "Fish - Betta splendens - Plakat - Siamese fighting fish", image: image1, price: 10.12, quantity: 1 },
        { id: 2, name: "Fish - Phenacogrammus interruptus - Congo tetra", image: image2, price: 5.19, quantity: 1 },
        { id: 3, name: "Fish - Thayeria boehlkei - Pinguin tetra", image: image3, price: 1.31, quantity: 1 },
        { id: 4, name: "Fish - Pterophyllum scalare - Angelfish", image: image4, price: 5.77, quantity: 1 },
        { id: 5, name: "Fish - Boeseman's rainbowfish Melanotaenia - Boesemani", image: image5, price: 4.90, quantity: 1 },
        { id: 6, name: "Fish - Ram cichlid - Mikrogeophagus ramirezi", image: image6, price: 4.61, quantity: 1 },
        { id: 7, name: "Fish - Corydoras aeneus sp.black venezuela", image: image7, price: 2.87, quantity: 1 },

    ]
    const [products, setProducts] = useState(initialProducts)
    const [toCart, setToCart] = useState([])

    const getProductId = (e) => {
        const idString = e.target.dataset.id
        const id = Number(idString)
        return id
    }

    const getProductById = (e) => {
        const id = getProductId(e)
        const itemFound = products.find(product => product.id === id)
        const foundedOrNot = toCart.find(product => product === itemFound)
        if (foundedOrNot === undefined) {
            setToCart([...toCart, itemFound])
        }
        else {
            const index = toCart.findIndex(product => product === itemFound)
            toCart[index].quantity = toCart[index].quantity + 1
        }

    }

    return (
        <div className="products">
            <Nav sendToCart={toCart} />
            <InsideCart sendCart={toCart} />
            <div className='container'>{products.map((product) => <Product onClick={getProductById} title={product.name} img={product.image} price={product.price} id={product.id} key={product.id} />)}</div>
        </div>
    );
};

Also add simple component which determines rendering what is inside the cart.

const OneProduct = (props) => {
    return (<div className='productincart'><div className='name'>{props.name}</div> <div className='price'>Price: {props.price}</div><div className='quantity'>{props.quantity}</div></div>)
}

Your event capture mechanism is incorrectly implemented.

for solution you should replace it with the following:

   <button onClick={() => showCart()}>SHOW CART</button>

You should check this link for the reason for the solution:

Event Handling Documentation

shortly, article includes this:

The problem with this syntax is that a different callback is created each time the LoggingButton renders. In most cases, this is fine. However, if this callback is passed as a prop to lower components, those components might do an extra re-rendering. We generally recommend binding in the constructor or using the class fields syntax, to avoid this sort of performance problem.

I already solved the problem. Issue was not using setToCart in product component. Thank you guys for all advices!

Updated code below:

  const getProductById = (e) => {
        const id = getProductId(e)
        const itemFound = products.find(product => product.id === id)
        const foundedOrNot = toCart.some(product => product === itemFound)
        if (foundedOrNot === false) {
            setToCart([...toCart, itemFound])
        }
        else {
            const index = toCart.findIndex(product => product === itemFound)
            const newCart = toCart.map(cart => {
                if (cart.id === index) {
                    cart.quantity = cart.quantity + 1
                    return cart
                }
                return cart
            })
            setToCart(newCart)
        }

    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM