-
Notifications
You must be signed in to change notification settings - Fork 321
Closed
Description
Hello,
Consider the following DSL (this is Feliz adapted to use Fable JSX module)
open Fable.Core
open Fable.Core.JsInterop
[<ImportMember("react")>]
[<AllowNullLiteral>]
type ReactElement = interface end
type private IReactProperty = JSX.Prop
[<Erase>]
type prop =
static member inline children(children: ReactElement list) : IReactProperty = "children", children
static member inline text(value: int) : IReactProperty = "children", [ JSX.text !!value ]
static member inline key(value: int) : IReactProperty = "key", string value
[<Erase>]
type Html =
static member inline fragment(children: ReactElement list) : ReactElement =
JSX.create "" [ "children" ==> children ] |> unbox
static member inline div(number: int) : ReactElement =
JSX.create "div" [ "children" ==> JSX.text (!!number) ] |> unbox
static member inline div(children: ReactElement list) : ReactElement =
JSX.create "div" [ "children" ==> children ] |> unbox
static member inline div(text: string) : ReactElement =
JSX.create "div" [ "children" ==> JSX.text text ] |> unbox
static member inline div(props: IReactProperty list) : ReactElement = JSX.create "div" props |> unbox
[<Erase; Mangle(false)>]
type Test =
[<ExportDefault>]
static member Test() =
Html.div
[
Html.div "Test 1"
Html.div "Test 2"
] |
export function Test() {
return <div>
<div>
Test 1
</div>
<div>
Test 2
</div>
</div>;
}
export default Test; |
which is fine as all the children are "static".
However if we do, we add a for loop, this transform the whole children list into a dynamic list.
[<Erase; Mangle(false)>]
type Test =
[<ExportDefault>]
static member Test() =
Html.div
[
Html.div "Test 1"
Html.div "Test 2"
for i in 0..2 do
Html.div [
prop.key i
prop.text i
]
] |
export function Test() {
return <div>
{toList(delay(() => append(singleton(<div>
Test 1
</div>), delay(() => append(singleton(<div>
Test 2
</div>), delay(() => map((i) => <div key={int32ToString(i)}>
{i}
</div>, rangeDouble(0, 1, 2))))))))}
</div>;
}
export default Test; |
This is problematic because now React will complain that not all child have a key prop.
We can work around this issue by wrapping the list in React.fragment, as it scope the dynamic list to only the for loop scope.
[<Erase; Mangle(false)>]
type Test =
[<ExportDefault>]
static member Test() =
Html.div
[
Html.div "Test 1"
Html.div "Test 2"
Html.fragment
[
for i in 0..2 do
Html.div [
prop.key i
prop.text i
]
]
] |
export function Test() {
return <div>
<div>
Test 1
</div>
<div>
Test 2
</div>
<>
{toList(delay(() => map((i) => <div key={int32ToString(i)}>
{i}
</div>, rangeDouble(0, 1, 2))))}
</>
</div>;
}
export default Test; |
However, this is a standard pattern in JSX and would be nice to be supported out of the box.
Candidate for the output would be something like:
export function Test() {
return <div>
<div>
Test 1
</div>
<div>
Test 2
</div>
{toList(delay(() => map((i) => <div key={int32ToString(i)}>
{i}
</div>, rangeDouble(1, 1, 10))))}
</div>;
}I think it should be doable, by detecting the toList call and extracting places where we see delay(() => append(singleton(...
Issue originally reported by @Freymaurer
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels