1

Edit: I have included the full code for better clarity

I am not sure if this is possible. I am trying to pass an onClick event via props but the click event does not work.

The parent component looks like this:

import React from 'react'
import { getProductsById } from '../api/get'
import Product from './Product'
import { instanceOf } from 'prop-types'
import { withCookies, Cookies } from 'react-cookie'

class Cart extends React.Component {
    static propTypes = {
        cookies: instanceOf(Cookies).isRequired
    }
    constructor(props) {
        super(props)
         const { cookies } = props;
            this.state = {
            prods: cookies.get('uircartprods') || '',
            collapsed: true,
            total: 0,
        }
        this.expand = this.expand.bind(this)
        this.p = [];
    }
    componentDidMount() {
        this.getCartProducts()
    }
    handleClick = (o) => {
        this.p.push(o.id)
        const { cookies } = this.props
        cookies.set('uircartprods', this.p.toString(), { path: '/' , sameSite: true})
        this.setState({prods: this.p })
        console.log('click')
    }
    getCartProducts = async () => {
        let products = []
        if (this.state.prods !== '') {
            const ts = this.state.prods.split(',')
            for (var x = 0; x < ts.length; x++) {
                var p = await getProductsById(ts[x])
                var importedProducts = JSON.parse(p)
                importedProducts.map(product => {
                    const prod = <Product key={product.id} product={product} handler={() => this.handleClick(product)} />
                    products.push(prod)
                })
            }
            this.setState({products: products})
        }
    }
    expand(event) {
        this.setState({collapsed: !this.state.collapsed})
    }
    handleCheckout() {
        console.log('checkout clicked')
    }
  render() {
    return (
            <div className={this.state.collapsed ? 'collapsed' : ''}>
                <h6>Your cart</h6>
                <p className={this.state.prods.length ? 'hidden' : ''}>Your cart is empty</p>
                {this.state.products}
                <h6>Total: {this.props.total}</h6>
                <button onClick={this.handleCheckout} className={this.state.prods.length ? '' : 'hidden' }>Checkout</button>
                <img src="./images/paypal.png" className="paypal" alt="Paypal" />
                <a className="minify" onClick={this.expand} alt="My cart"></a>
                <span className={this.state.prods.length ? 'pulse' : 'hidden'}>{this.state.prods.length}</span>
            </div>
        )
  }
}
    
export default withCookies(Cart)

The Product component:

import React from 'react';

class Product extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            showDetails: false,
            showModal: false,
            cart: []
        }
        this.imgPath = './images/catalog/'
    }
    render() {
    return (
        <div className="Product">
            <section>
                <img src={this.imgPath + this.props.product.image} />
            </section>
            <section>
                <div>
                    <h2>{this.props.product.title}</h2>
                    <h3>{this.props.product.artist}</h3>
                    <p>Product: {this.props.product.product_type}</p>
                    <h4>&#36;{this.props.product.price}</h4>
                    <button className="button" 
                    id={this.props.product.id} onClick={this.props.handler}>Add to cart</button>
                </div>
            </section>
        </div>
        )
    }
}

export default Product

If I log this.props.handler I get undefined. Everything works apart from the click handler, I was wondering if it might have something to with the async function. I am very new to React, there are still some concepts I'm not sure about, so any help is appreciated.

2
  • Your handler is creating a new function instead of passing a function. It should be handler={this.handleClick} Commented Oct 12, 2020 at 23:52
  • Can you post the complete code? There appear to be missing parts. What is importedProducts? What do you intent to do with handleClick? Commented Oct 12, 2020 at 23:52

1 Answer 1

3

Okay, I see a few issues here.

First, there is no need to call this.handleClick = this.handleClick.bind(this) in the constructor, because you are using an arrow function. Arrow functions do not have a this context, and instead, accessing this inside your function will use the parent this found in the Class.

Secondly, it is wrong to store components in state. Instead, map your importedProducts inside the render function.

Thirdly, the issue with your handler is that this.props.handler doesn't actually call handleClick. You will notice in the definition handler={(product) => this.handleClick} it is returning the function to the caller, but not actually calling the function.

Try this instead.

class Product extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    return (
      <div>
        <button className="button" id={this.props.product.id} onClick={this.props.handler}>
          Add to cart
        </button>
      </div>
    );
  }
}

export default Product;
import Product from './Product'

class Cart extends React.Component {
  constructor(props) {
    super(props);
  }

  handleClick = (o) => {
    console.log('click');
  };

  render() {
    return (
      <div>
        {importedProducts.map((product) => {
          return <Product key={product.id} product={product} handler={() => this.handleClick(product)} />;
        })}
      </div>
    );
  }
}

export default Cart;
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.