1

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

0

3 Answers 3

1

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

Sign up to request clarification or add additional context in comments.

1 Comment

glad to have helped :)
0

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

1 Comment

It works for only one line. But if orderlines more than one? this.myOrder.append(instance) maybe
0

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

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.