ReactJS:在这种情况下,绑定如何工作?

时间:2020-06-30 10:06:37

标签: javascript reactjs

我目前正在构建具有“添加到购物车”功能的电子商务网站,我在“购物车”类中工作。我正在使用Redux - onDelete函数用于存在“删除”按钮的情况,并且可以通过单击(调用onClick)将其从当前购物车状态中移除。

这是我一直在尝试的方法,但是它不起作用并抛出错误:“ TypeError:无法读取未定义的属性'onClick'”。

您可以看到我已经将 this 传递给了构造函数中的onClick函数,因此在Button的onClick属性中,我只是将cartID传递给了onClick函数:

Cart.js文件

class Cart extends React.Component {
    constructor() {
        super();
        this.onClick = this.onDelete.bind(this);
    }

    onDelete(_id) {
    //
    }

    render() {
        // if more than 1 item in cart array, then render the cart
        // otherwise, render empty
        if(this.props.cart[0]) {
            return this.renderCart();
        } else {
            return this.renderEmpty();
        }       
    }

    renderEmpty() {
        return (<div>Empty Cart</div>)
    }

    renderCart() {
        
        const cartItemsList = this.props.cart.map(function(cartArr) {
            return (
                <Card key={cartArr._id}>
                    <Row>
                        <Col>
                            <h6>{cartArr.title}</h6>
                        </Col>
                        <Col>
                            <h6>USD {cartArr.price}</h6>
                        </Col>
                        <Col>
                            <h6>qty. goes here</h6>
                        </Col>
                        <Col>
                            <ButtonGroup style={{minWidth:'300px'}}>
                                <Button
                                    variant = "default"
                                    size    = "small">
                                    -
                                </Button>
                                <Button
                                    variant = "default"
                                    size    = "small">
                                    +
                                </Button>
                                <span>     </span>
                                <Button
                                    onClick = {this.onClick(cartArr._id)}
                                    variant = "danger"
                                    size    = "small">
                                    DELETE
                                </Button>
                            </ButtonGroup>
                        </Col>
                    </Row>
                </Card>
            )
        })

        return (
            <Card>
                {cartItemsList}
            </Card>
        )
    }
}

我知道部分原因是我传递给onClick函数的this关键字的性质。当我按照教程进行并在cartItemList的末尾添加this关键字时,效果很好:

class Cart extends React.Component {
    constructor() {
        super();
        this.onClick = this.onDelete.bind(this);
    }

    onDelete(_id) {
    //
    }

    render() {
        // if more than 1 item in cart array, then render the cart
        // otherwise, render empty
        if(this.props.cart[0]) {
            return this.renderCart();
        } else {
            return this.renderEmpty();
        }       
    }

    renderEmpty() {
        return (<div>Empty Cart</div>)
    }

    renderCart() {
        
        const cartItemsList = this.props.cart.map(function(cartArr) {
            return (
                <Card key={cartArr._id}>
                    <Row>
                        <Col>
                            <h6>{cartArr.title}</h6>
                        </Col>
                        <Col>
                            <h6>USD {cartArr.price}</h6>
                        </Col>
                        <Col>
                            <h6>qty. goes here</h6>
                        </Col>
                        <Col>
                            <ButtonGroup style={{minWidth:'300px'}}>
                                <Button
                                    variant = "default"
                                    size    = "small">
                                    -
                                </Button>
                                <Button
                                    variant = "default"
                                    size    = "small">
                                    +
                                </Button>
                                <span>     </span>
                                <Button
                                    onClick = {this.onClick(cartArr._id)}
                                    variant = "danger"
                                    size    = "small">
                                    DELETE
                                </Button>
                            </ButtonGroup>
                        </Col>
                    </Row>
                </Card>
            )
        })

        return (
            <Card>
                {cartItemsList}
            </Card>
        )
    }
}

4 个答案:

答案 0 :(得分:3)

 onClick = {this.onClick(cartArr._id)}

将此行更改为

 onClick = {() => this.onClick(cartArr._id)}

答案 1 :(得分:2)

使用您的语法

onClick = {this.onClick(cartArr._id)}

该函数被立即调用,而不是单击。

您需要

onClick = {() => this.onClick(cartArr._id)}

相反。

无论如何,现代ES无需手动绑定东西;改用箭头功能。

这是我编写组件的方式(如果它必须是类组件,而不是功能组件):

class Cart extends React.Component {
  // Arrow functions are automagically bound
  onDelete = (_id) => {
    const { cart } = this.props;
    const cartWithoutGivenId = cart.filter((item) => item._id !== _id);
    const cartAfterDelete = { books: cartWithoutGivenId };
    this.props.deleteFromCart(cartAfterDelete);
  };

  render() {
    const { cart } = this.props;
    if (!cart.length) {
      return <div>Empty Cart</div>;
    }

    const cartItemsList = cart.map((item) => (
      <Card key={item._id}>
        <Row>
          <Col>
            <h6>{item.title}</h6>
          </Col>
          <Col>
            <h6>USD {item.price}</h6>
          </Col>
          <Col>
            <h6>qty. goes here</h6>
          </Col>
          <Col>
            <ButtonGroup style={{ minWidth: "300px" }}>
              <Button variant="default" size="small">
                -
              </Button>
              <Button variant="default" size="small">
                +
              </Button>
              <Button
                onClick={() => this.onDelete(item._id)}
                variant="danger"
                size="small"
              >
                DELETE
              </Button>
            </ButtonGroup>
          </Col>
        </Row>
      </Card>
    ));

    return <Card>{cartItemsList}</Card>;
  }
}

编辑

为完整起见,这里有一对功能组件:

const CartItem = ({ item, onDelete }) => (
  <Card>
    <Row>
      <Col>
        <h6>{item.title}</h6>
      </Col>
      <Col>
        <h6>USD {item.price}</h6>
      </Col>
      <Col>
        <h6>qty. goes here</h6>
      </Col>
      <Col>
        <ButtonGroup style={{ minWidth: "300px" }}>
          <Button variant="default" size="small">
            -
          </Button>
          <Button variant="default" size="small">
            +
          </Button>
          <Button
            onClick={() => onDelete(item._id)}
            variant="danger"
            size="small"
          >
            DELETE
          </Button>
        </ButtonGroup>
      </Col>
    </Row>
  </Card>
);

const Cart = ({ cart, deleteFromCart }) => {
  const onDelete = React.useCallback(
    (_id) => {
      const cartWithoutGivenId = cart.filter((item) => item._id !== _id);
      const cartAfterDelete = { books: cartWithoutGivenId };
      deleteFromCart(cartAfterDelete);
    },
    [cart],
  );

  if (!cart.length) {
    return <div>Empty Cart</div>;
  }

  return (
    <Card>
      {cart.map((item) => (
        <CartItem key={item._id} item={item} onDelete={onDelete} />
      ))}
    </Card>
  );
};

答案 2 :(得分:1)

您应该使用currying。

当您编写this.onClick(cartArr._id)时,它的值将为undefined,但希望获得一个回调函数。因此,您需要从onDelete返回一个函数,如下所示:

onDelete(id) {
    return function() {
         //On delete logic
    }
}

通过这种方式,您可以避免通过使用类属性和箭头函数(https://medium.com/quick-code/react-quick-tip-use-class-properties-and-arrow-functions-to-avoid-binding-this-to-methods-29628aca2e25)来绑定回调

希望如此,祝您好运!

答案 3 :(得分:1)

除了其他答案外,我还要添加解释为什么,您的代码会引发df.rename(columns={"1999q4": "Quarter", 9926.1: "GDP"}, inplace = True) 错误。

您根据map docs"TypeError: Cannot read property 'onClick' of undefined".回调定义为常规函数(不是箭头函数):

如果提供了thisArg参数,它将用作回调的this 值。否则,将使用undefined值作为此值。

因此map回调中的thismap,这就是为什么会出错的原因。尽管undefined函数已正确地“绑定”,但您无法访问此函数,因为onClick回调中的this并不指向组件实例。要解决此问题,您可以将箭头函数用作map回调而不是常规函数(因为使用了封闭词法作用域的箭头函数map内部)。