I would like to make use of a component that is defined afterwards. For example:
// TreeItem uses TreeList
module TreeItem = {
@react.component
let make = (~item: item) => {
<>
<li id=item.id>{React.string(item.name)}</li>
<TreeList items=item.items /> /* this throws an error */
</>
}
}
// and TreeList uses TreeItem
module TreeList = {
@react.component
let make = (~items: array<item>) => {
<ul>
{items
->Belt.Array.map(item => <TreeItem item=item />)
->React.array}
</ul>
}
}
however the previous code throws the following error:
The module or file TreeList can't be found.
How can I use a component even if it has been defined afterward?
We can use the and
keyword to declare “recursive modules”. Found here:
// Recursive modules require signatures.
module type TreeItemType = {
@react.component
let make: (~item: item) => React.element
}
module type TreeListType = {
@react.component
let make: (~items: array<item>) => React.element
}
// Defines a recursive module.
module rec TreeItem: TreeItemType = {
@react.component
let make = (~item: item) => {
<>
<li id=item.id>{React.string(item.name)}</li>
<TreeList items=item.items />
</>
}
}
// Thanks to the `and` keyword `TreeItem` knows `TreeList` in advance.
// The `and` keyword can be used in recursive functions as well.
and module TreeList: TreeListType = {
@react.component
let make = (~items: array<item>) => {
<ul>
{items
->Belt.Array.map(item => <TreeItem item=item />)
->React.array}
</ul>
}
}
Mamita linda!
3 Likes
You can annotate the signatures like normal types:
module rec TreeItem: {
...
} = {
...
}
and module TreeList: {
...
} = {
...
}
6 Likes
wels
4
Is there a way of doing this in two seperate files? One for the TreeItem recursive module, and another for the TreeList recursive module?
Thanks
Not in separate files, no.
1 Like