Skip to content
Advertisement

Updating state inside child and using updated value in parent

I am trying to create a really basic header mini cart with cart item counter in NextJS. Im using the form state value in the header component and then using that value in the child components of the header where the numerical value is rendered.

Currently I have the total item count show correctly when I submit my form and I can see the correct value of items showing in the header counter and the mini cart item as expected.

However, when I click to remove the item in the mini cart I would like to reset the entire counter state back to 0 from whatever its previous value was and re-render the header and mini cart/cart item components so that the product item is hidden in the mini cart again.

Here is a basic run through of current components.

product-form.js

import React, { useState, useRef, useEffect } from "react";

export default function ProductForm(props) {
  const [count, setCount] = useState(0);

  const numberInput = useRef(null);

  useEffect(() => {
    numberInput.current.dispatchEvent(
      new Event("change", {
          detail: {
              newValue: count,
          },
          bubbles: true,
          cancelable: true,
      })
    );
  }, [count]);

  render(
    <>
     <div>
        <button onClick={() => {setCount(count - 1)}}>>
         Decrease
        </button>
       <Input 
        value={count}
        ref={numberInput}
        onChange={(e) => setNumberValue(e.target.value)}>
        <button onClick={() => {setCount(count + 1)}}>>
         Increase
        </button>
     </div>
     <button onClick={event => props.onClick(() => event.currentTarget.parentNode.parentNode.querySelector('#product-qty-input').value)}>Add to Cart</button>
    </>
  )
}

header.js

import React, { useState } from "react";
import MiniCart from './minicart'

export default function HeaderRight({count}) {
  const [cartItemCount, setCartItemCount] = useState([]);
  return (
    <>
     <span>You have {count} items </span>
     <MiniCart count={count} />
    </>
  )
}

mini-cart.js

import CartItem from "./cartitem";
import CartEmpty from "./cartEmpty";

export default function MiniCart({count}) {
  return (
    <>
     { count == 0 && 
       <CartEmpty />
     }
     { count > 0 &&
        <CartItem count={count} />
     }
    </>
  )
}

mini-cart-item.js

export default function CartItem({count}) {
  return (
    <>
      <p>Product Name</p>
      <p>Unit Price: $125.00</p>
      <p>x{count}</p>
      <p>$375.00</p>
      <button>REMOVE ITEM</button>
    </>
  )
}

UPDATE 07/09/2022:

I have fixed this issue. Issue was resolved by passing setCartCountState as a value into all of the nested children components. This then allowed me to create a click event in the mini-cart-item.js component that would allow me to use the following function to reset the counter back to 0 and hide the mini cart items.

// Reset 'countState' to '0' so that item is removed when remove item is clicked in mini cart.
  const changeState = () => {
    countState("0");
}

Answer can be demoed here: https://stackblitz.com/edit/nextjs-lzqu46?file=components/cartitem.js

Advertisement

Answer

Where does the count of HeaderRight come from? All the rendering logic comes from this value. If this is a state, pass down also its set function to CartItem. Then you can do the following with the button:

<button onClick={setCount(count - 1)}>REMOVE ITEM</button>

The CartItem component would look like:

export default function CartItem({count, setCount}) {
  return (
    <>
      <p>Product Name</p>
      <p>Unit Price: $125.00</p>
      <p>x{count}</p>
      <p>$375.00</p>
      <button onClick={() => setCount(count - 1)}>REMOVE ITEM</button>
    </>
  )
}
User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement