Vadym
Vadym

Reputation: 1555

ReactJS. How to call component's method from parent component

My example is a simple order form. I have a main component (Order) and inside this component I render dynamic list of child components (OrderLine)

class Order extends React.Component {
  ...
  render() {
    return <div>
      <strong>Total: $ {this.getTotal()}</strong>
      <table id='orderlines' style={tableStyles}>
        <tbody>
          {this.getLines()}
        </tbody>
      </table>
    </div>
  }

  getLines = () => {
    return this.state.orderLines.map((item, _) =>
      <OrderLine key={item.id} {...item} />)
  }
}

Child component (OrderLine) has input (quantity) and method getTotal() which calculates the sum for this line

getTotal = () => (this.props.product.price * this.state.quantity).toFixed(2);

The goal is to calculate total sum for the Order.

I want to do something like sum(map(allOrderLines, (line) => line.getTotal())) but I can't get access to orderLine.getTotal() from the Order component.

So, what is the best way to do it? I know how to update parent's state (give callback function as prop) from child, but is it possible to do it from parent?

Full example here:

Edit Order component example

Upvotes: 1

Views: 82

Answers (3)

Shubham Khatri
Shubham Khatri

Reputation: 281626

Attach a ref instance to your orderlines and call the function like

orderLinesRef = [];
getLines = () => {
    return this.state.orderLines.map((item, _) => (
      <OrderLine
        key={item.id}
        ref={ref => (this.orderLinesRef[_] = ref)}
        updateCallback={this.updateTotal}
        {...item}
      />
    ));
  };

Edit Order component example

Upvotes: 1

Chase DeAnda
Chase DeAnda

Reputation: 16441

I think the easiest option would be to move getTotal into the parent Order component and pass it down as a prop to each OrderLine. Then, both components will have access to that utility function.

Order.js

render() {
    const { id, product } = this.props;
    return (
      <tr key={id}>
        ...
        <td>
          {this.props.getTotal(this.props.product.price, this.state.quantity)}
        </td>
      </tr>
    );
  }

OrderLine.js

  updateTotal = () => {
    // You'll need a way to get the product price and quantity for each order line
    let total = this.state.orderLines.reduce((sum, line) => {
      sum = sum + this.getTotal(line.product.price, line.quantity);
    }, 0);

    this.setState({ total });
  };

Edit Order component example

Upvotes: 0

MBehtemam
MBehtemam

Reputation: 7919

you can add ref like this to order line

getLines = () => {
return this.state.orderLines.map((item, _) =>
  <OrderLine 
  ref={instance => this.myOrder = instance}
    key={item.id} 
    updateCallback={this.updateTotal}
    {...item} 
  />)

now you can access methods of OrderLine via this.myOrder

Edit Order component example

Upvotes: 0

Related Questions