Search code examples
reasonreason-react

Variable number of children


Background: I'm going through an official React tutorial (https://reactjs.org/tutorial/tutorial.html), but in ReasonML (ReasonReact v. 0.9.1). This is a tic-tac-toe game. The classic game is played on a 3x3 board, and I have it working, but now I'm trying to extend it to an arbitrary square board size. The code I have for the hard-coded 3x3 board looks like follows:

let renderSquare = (...) =>
  <Square ... />;

[@react.component]
let make = (~onClick, ~squares, ~winner) => {
...
  let render = i =>
    renderSquare(...);
  
  <div>
    <div className="board-row"> {render(0)} {render(1)} {render(2)} </div>
    <div className="board-row"> {render(3)} {render(4)} {render(5)} </div>
    <div className="board-row"> {render(6)} {render(7)} {render(8)} </div>
  </div>;

The Square is another component of mine. What I'm trying to achieve is to add an arbitrary amount of Squares into each row of the board, and to have an arbitrary number of rows.

What I came up with so far doesn't work, because I cannot figure out how to pass an array or a list of React.element as children to a <div />. The smallest possible code that shows this problem looks like this:

let renderRow(squares) = <div>(squares |> Array.map(render))</div>;

Here the squares is of type array(int). This function doesn't compile with the following error (the error points to the code inside the div above):

  This has type:
    array(React.element)
  But somewhere wanted:
    React.element

My question is, what is the right way to have an arbitrary number of children to a <div/> or any other JSX component (not sure if my terminology is straight here). Looks like an array is not the way to go. Is it even possible? If it's not possible, what's the idiomatic way in ReasonReact (or, maybe, just in React) to solve this problem?


Solution

  • There's a function, React.array, that you need to use to convert an array of elements into a single element:

    let renderRow(squares) = <div>(squares |> Array.map(render) |> React.array)</div>;