I’m creating a module signature and I would like to make a react component optional. I haven’t found a way yet how to do it? In the example below, I would like to make PageSubtitle optional so if I create a module of the type LibraryType I would not always have to provide it. Does anybody have a solution for this? The rescript docs don’t seem to mention anything about optional modules.
module type LibraryType = {
module PageTitle: {
@react.component
let make: (~title: string) => React.element
}
// This should be optional
module PageSubtitle: {
@react.component
let make: (~subtitle: string) => React.element
}
}
I would like to pass a module Library with react components to a module Menu for instance. If the Library has a PageSubtitle component it will use it if not it will use its own.
But I guess I could use records. Buy I just thought if I could make PageTitle module optional it would be cleaner.
Thank you @tsnobip That could be a solution. I’m not sure how it would keep the code more simple.
For now this is what I’m thinking of doing but I would very much welcome any other ideas.
I would like to avoid having to add this line in module Library2 if possible. At the moment, I don’t know how to do it. module PageSubtitle = PageSubtitle
module type LibraryType = {
module PageTitle: {
@react.component
let make: (~title: string) => React.element
}
module PageSubtitle: {
@react.component
let make: (~subtitle: string) => React.element
}
}
module DefaultLibrary: LibraryType = {
module PageTitle = {
@react.component
let make = (~title: string) => {
<h1 className="text-4xl font-bold"> {React.string(title)} </h1>
}
}
module PageSubtitle = {
@react.component
let make = (~subtitle: string) => {
<h1 className="text-lg font-bold"> {React.string(subtitle)} </h1>
}
}
}
module Library1: LibraryType = {
module PageTitle = {
@react.component
let make = (~title: string) => {
<h1 className="text-2xl font-bold text-primary"> {React.string(title)} </h1>
}
}
module PageSubtitle = {
@react.component
let make = (~subtitle: string) => {
<h1 className="text-xl font-bold"> {React.string(subtitle)} </h1>
}
}
}
module Library2: LibraryType = {
open DefaultLibrary
module PageTitle = {
@react.component
let make = (~title: string) => {
<h1 className="text-2xl font-bold text-on-background"> {React.string(title)} </h1>
}
}
module PageSubtitle = PageSubtitle
}
module type CustomizableMenuType = (Library: LibraryType) =>
{
@react.component
let make: (~menu: Menu.t) => React.element
}
module CustomizableMenu: CustomizableMenuType = (Library: LibraryType) => {
@react.component
let make = (~menu: Menu.t) => {
<div>
<Library.PageTitle title="Hello World" />
<Library.PageSubtitle subtitle="This is a very interesting subtitle" />
</div>
}
}
module CustomizableMenuInstance1 = CustomizableMenu(Library1)
module CustomizableMenuInstance2 = CustomizableMenu(Library2)
It depends how often you want to customize the optional fields, if most of the times you want the default, then using first class modules is likely easier. I don’t have access to my computer until Monday so I can’t write down an example before.
I think I would always be passing a few customised values to the optional fields, but hardly ever all of them. I am curious to see an example using first class modules. I’m not very familiar with their syntax in Rescript and there isn’t much documentation.
And here is a demo using a record, it’s likely the most cumbersome of all the variants.
To be honest I’d still use your solution, it’s simpler and more explicit, this way you won’t forget to define custom components when you add new “optional” ones.
Thank you @tsnobip. I think the first example is the best option of all. I wasn’t sure how to turn a function parameter (the value of which is a module/react component) back to a module/react component inside the body of the function. The keyword unpack is what I was after. I couldn’t find any documentation on rescript’s website for it.