Search code examples
reasonreason-react

Passing React Component to Another Component?


I'm trying to define a ProductRow and ProductCategoryRow from Thinking in React.

productRow.re

let component = ReasonReact.statelessComponent("ProductRow");

let make = (~name, ~price, _children) => {
  ...component,
  render: (_self) => {
    <tr>
      <td>{ReasonReact.stringToElement(name)}</td>
      <td>{ReasonReact.stringToElement(price)}</td>
    </tr>
  }
};

productCategoryRow.re

let component = ReasonReact.statelessComponent("ProductCategoryRow");

let make = (~title: string, ~productRows, _children) => {
  ...component,
  render: (_self) => {
    <div>
        <th>{ReasonReact.stringToElement(title)}</th>
    </div>
  }
};

I believe that I need to map over the productRows, i.e. List of ProductRow's, with a function of: productRow => <td>productRow</td>.

How can I do that in this example?

Or, if I'm completely off the mark, please explain how I can achieve the above.


Solution

  • In the 'Thinking in React' page, the component nesting hierarchy is such that a ProductTable contains several ProductRows. We can model that in ReasonReact by mapping over an array of products and producing ProductRows as the output. E.g.:

    type product = {name: string, price: float};
    
    /* Purely for convenience */
    let echo = ReasonReact.stringToElement;
    
    module ProductRow = {
      let component = ReasonReact.statelessComponent("ProductRow");
      let make(~name, ~price, _) = {
        ...component,
        render: (_) => <tr>
          <td>{echo(name)}</td>
          <td>{price |> string_of_float |> echo}</td>
        </tr>
      };
    };
    
    module ProductTable = {
      let component = ReasonReact.statelessComponent("ProductTable");
      let make(~products, _) = {
        ...component,
        render: (_) => {
          let productRows = products
            /* Create a <ProductRow> from each input product in the array. */
            |> Array.map(({name, price}) => <ProductRow key=name name price />)
            /* Convert an array of elements into an element. */
            |> ReasonReact.arrayToElement;
    
          <table>
            <thead>
              <tr> <th>{echo("Name")}</th> <th>{echo("Price")}</th> </tr>
            </thead>
            /* JSX can happily accept an element created from an array */
            <tbody>productRows</tbody>
          </table>
        }
      };
    };
    
    /* The input products. */
    let products = [|
      {name: "Football", price: 49.99},
      {name: "Baseball", price: 9.99},
      {name: "Basketball", price: 29.99}
    |];
    
    ReactDOMRe.renderToElementWithId(<ProductTable products />, "index");