Recursive React component

Hi, I have a problem making a component like this:

    type rec tree = {
      id: string,
      children: array<tree>,
    }

    module Tree = {
      @react.component
      let rec make = (~tree) => {
        <div>
          {tree.id->React.string}
          {tree.children
          ->Js.Array2.map(tree => React.createElement(make, {"tree": tree}))
          ->React.array}
        </div>
      }
    }

It compile but with a warning:

    Compiled with 1 Warning(s)

    [W] Line 8, column 10:
    unused rec flag.

https://rescript-lang.org/try?code=C4TwDgpgBAThDGVh2gXigbwFBSgSwBMAuKAZ2TwDsBzAGhyngAs8AbAuSkgQxhm5AAeZBAgA+egF8sWALYB7AgFdW0ACooo6bLgACcbvGAA6ePNlh5lCJWANVwWAiizuAazRQAFAD8REAEotMUwGXEECPAA3MTDcTH9jQgBaMQAlCEMTchgqaml4+IxE5jYOGzjcVIApUmMAQT4BACZjVzAvf2CoDKzTA2AIAFFVWRtgL1cPWkwAIn9Zkn9JAIDKqFTeo2NefhAC+MEAekiYhmlpIA

Any idea ?

An alternative is to make recursive module

    type rec tree = {
      id: string,
      children: array<tree>,
    }

    module rec Tree: {
       let make: {"tree": tree} => React.element
       let makeProps: (~tree: 'tree, ~key: string=?, unit) => {"tree": 'tree}
    } = {
      @react.component
      let make = (~tree) => {
        <div>
          {tree.id->React.string}
          {tree.children
          ->Js.Array2.map(tree => <Tree tree />)
          ->React.array}
        </div>
      }
    }

https://rescript-lang.org/try?code=C4TwDgpgBAThDGVh2gXigbwFBSgSwBMAuKAZ2TwDsBzAGhyngAs8AbAuSkgQxhm5AAeZBAgA+egF8sWALYB7AgFdW0OIgAqKEtlxRVwKLO4BrCDoBEIiBZLXJUVGKgAlCN3jAAdBFWyIlMAM+hCGxmYACjDyYKQkABQAftYkAOTWtFCJZiAk5DBU1KgA-JlKlHjAAJSOzhhWKLZQ6SjSDui6UAACcB7e8PKyYPKUAUG4BkamaFBJ1jVOmMFQggR4AG5iy7gY1l6EALRibn1e+YXSenq7KF7MbBwB21BHAFKkXgCCfAIATF7GMDxay1FZaURIFBQAD0YiqzyOJ08Xl4-BAlz0gmha02DDaWCAA

but typing is redundant, it’s too verbose in my opinion (And JS output is :zipper_mouth_face:)

How can I do better ?

Thanks.

1 Like

You can use @react.component in module signatures too:

module rec Tree: {
  @react.component
  let make: (~tree: tree) => React.element
} = {
 ...
}
2 Likes

Thanks, you’re right, it’s better … but it still not very pretty
And Js output is still the same, not as clean as putting the make function recursive

/*
module Tree = {
  @react.component
  let rec make = (~tree) => { ...
*/
'use strict';

var React = require("react");

function make(Props) {
  var tree = Props.tree;
  return React.createElement("div", undefined, tree.id, tree.children.map(function (tree) {
                  return React.createElement(make, {
                              tree: tree
                            });
                }));
}

var Tree = {
  make: make
};

exports.Tree = Tree;

VS

/*
module rec Tree: {
  @react.component
  let make: (~tree: tree) => React.element
} = {
  let make = (~tree) => { ...
*/
'use strict';

var React = require("react");
var Caml_module = require("./stdlib/caml_module.js");

var Tree = Caml_module.init_mod([
      "playground.res",
      9,
      4
    ], {
      TAG: /* Module */0,
      _0: [[
          /* Function */0,
          "make"
        ]]
    });

function Playground$Tree(Props) {
  var tree = Props.tree;
  return React.createElement("div", undefined, tree.id, tree.children.map(function (tree) {
                  return React.createElement(Tree.make, {
                              tree: tree
                            });
                }));
}

Caml_module.update_mod({
      TAG: /* Module */0,
      _0: [[
          /* Function */0,
          "make"
        ]]
    }, Tree, {
      make: Playground$Tree
    });

exports.Tree = Tree;

I found that I can deactivate the warning using

module Tree = {
  @@warning("-39")
  @react.component
  let rec make = (~tree) => { ... }
  @@warning("+39")
}

Not very pretty but waiting for better …

Thanks anyway :wink: