简体   繁体   中英

How to pass quantity from component to component in ReactJS where they are independent but live in the same parent

I have the following class Component that is handling some quantity changes an updating the price of a sku from stripes API.

The crux of the issue is that I need the quantity for the sku inside the Cart component, but the quantity state is handled inside the Product component, and it needs to be separate because you can change the sku in the dropdown menu and the product will change state, so if the cart component is in the product then the state clears and is not persistent. Also I will need a way for the cart to add to the state instead of just replacing it on setSkuObject not sure if that's possible either

Any help would be greatly appreciated

Product component


  class Product extends React.Component {
    constructor(props) {
      super(props)
  
      this.state = {
        stripe: null,
        quantity: 1,
        price: props.price,
        skuObject: null,
      }
  
      this.handleInputChange = this.handleInputChange.bind(this)
    }
    
  
    handleInputChange(event) {
      const target = event.target
      const { quantity } = this.state
      const { price } = this.props
  
  
      this.setState({
        quantity: parseInt(target.value),
      })
      this.setState({
        price: price * parseInt(target.value),
      })
    }
  
    render() {
      const { id, currency, name, productId } = this.props
      const { quantity, price, skuObject } = this.state
  
      //console.log(quantity);
  
      const priceFloat = (price / 100).toFixed(2)
      const formattedPrice = Intl.NumberFormat("en-US", {
        style: "currency",
        currency,
      }).format(priceFloat)
  
      return (
        <>
          <form className="name-buy">
            <label>
              Quantity
              <input
                type="number"
                name="amount"
                min="1"
                value={this.state.quantity}
                onChange={this.handleInputChange}
              />
            </label>
          </form>
          <form
            className="submit"
            onSubmit={this.handleSubmit(id, productId, quantity)}
          >
            <div>
              <h2>
                {name} ({formattedPrice})
              </h2>
              <button type="submit">Buy Now</button>
            </div>
          </form>
        </>
      )
    }
  }

cart class component

class Cart extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      sku: null,
      quantity: null,
    }
  }
  render() {
    const { skuObject } = this.props
    return <CartBox>Cart {skuObject} {/*would like to have quantity here*/} </CartBox>
  }
}

It lives inside A StoreDetails functional component

const StoreDetails = ({ data, location }) => {
    const setSkuOnce = data.allDatoCmsStore.edges.map(
      ({ node: product }, index) => {
        if (product.defaultProduct === true) {
          //console.log(product.skuId);
          return product.skuId
        }
      }
    )
  
    //console.log(setSkuOnce)
  
    var filtered = setSkuOnce.filter(function(el) {
      return el != null
    })
  
    const [value, setValue] = useState({
      skuId: filtered[0],
    })
  
    const run = event => {
      //console.log(event);
      setValue({ skuId: event })
    }
  
    const [skuObject, setSkuObject] = useState()
    const handleCart = (sku, productId, quantity) => {
      return event => {
        event.preventDefault()
        setSkuObject(sku)
      }
    }
  
    return (
      <Layout>
        <StoreHero>
          <Link to="/store">
            <BsArrowLeft />
            Back
          </Link>
          <Alert test="test" hello="hello" hash={location.hash} />
  
          {/* <ShowItem props={data}/> */}
  
          <Cart skuObject={skuObject} />
  
          {data.allDatoCmsStore.edges.map(({ node: sku }) => (
            <React.Fragment key={sku.skuId}>
              {value.skuId === sku.skuId ? (
                <ProductGrid>
                  <Img fluid={sku.image.fluid} />
                  <ProductCol>
                    <h1>{sku.productTitle}</h1>
                    <FirstThreeWrap>
                      <form className="variant">
                        <label>
                          <span>Product Variant</span>
                          <select
                            value={value.skuId}
                            onChange={event => run(event.target.value)}
                          >
                            {data.allDatoCmsStore.edges.map(({ node: sku }) => (
                              <React.Fragment key={sku.skuId}>
                                <option value={sku.skuId}>{sku.title}</option>
                              </React.Fragment>
                            ))}
                          </select>
                        </label>
                      </form>
  
                      {/* <ShowItem setValue={setValue}/> */}
                      <Product
                        key={sku.id}
                        id={sku.skuId}
                        productId={sku.productId}
                        currency="cad"
                        price={sku.price}
                        name={sku.title}
                      />
                      <button onClick={handleCart(sku.skuId, sku.productId)}> {/* I NEED TO PASS THE QUANTITY IN HERE */}
                        Add to Cart
                      </button>
                    </FirstThreeWrap>
                    <div
                      className="description"
                      dangerouslySetInnerHTML={{ __html: sku.productDescription }}
                    />
                    <QuestionForm skuId={sku.skuId} name={sku.title} />
                  </ProductCol>
                </ProductGrid>
              ) : null}
            </React.Fragment>
          ))}
        </StoreHero>

      </Layout>
    )
  }

If I've parsed all this correctly, then it would seem you could achieve it by simply moving the "Add To Cart" button inside Product . I can't see any reason not to as they are rendered one after the other and use exactly the same data from the map function. You would just pass the handler down like so:

<Product
  key={sku.id}
  id={sku.skuId}
  productId={sku.productId}
  currency="cad"
  price={sku.price}
  name={sku.title}
  handleCart={handleCart}
/>

And then in Product render it like this:

return (
  <>
    <form>
      ...
    </form>
    <button onClick={() => this.props.handleCart(id, productId, this.state.quantity)}>
      Add to Cart
    </button>
  </>
)

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