Skip to content

Commit e5ed303

Browse files
zaaackalfonsogarciacaro
authored andcommitted
Add React Component Support
1 parent 1d5fbc9 commit e5ed303

18 files changed

+1276
-771
lines changed

.paket/Paket.Restore.targets

Lines changed: 267 additions & 0 deletions
Large diffs are not rendered by default.

Samples/SSRSample/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
"dependencies": {
44
"babel-polyfill": "6.26.0",
55
"babel-runtime": "6.26.0",
6-
"react": "16.0.0",
6+
"react": "16.2.0",
77
"react-bootstrap": "0.31.3",
8-
"react-dom": "16.0.0",
8+
"react-dom": "16.2.0",
99
"remotedev": "0.2.7"
1010
},
1111
"devDependencies": {
@@ -15,7 +15,7 @@
1515
"babel-preset-env": "1.6.0",
1616
"concurrently": "3.5.0",
1717
"fable-loader": "1.1.3",
18-
"fable-splitter": "^0.1.21",
18+
"fable-splitter": "0.1.21",
1919
"fable-utils": "1.0.6",
2020
"webpack": "3.7.1",
2121
"webpack-dev-server": "2.9.1"

Samples/SSRSample/splitter.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ function resolve(relativePath) {
66
}
77

88
module.exports = {
9-
entry: resolve("src/MyProject.fsproj"),
9+
entry: resolve("src/Client/Client.fsproj"),
1010
outDir: resolve("out"),
1111
babel: fableUtils.resolveBabelOptions({
1212
presets: [["env", { modules: "commonjs" }]],

Samples/SSRSample/src/Client/Client.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ Program.mkProgram init update view
5151
|> Program.withConsoleTrace
5252
|> Program.withHMR
5353
#endif
54-
|> Program.withReact "elmish-app"
54+
|> Program.withReactHydrate "elmish-app"
5555
#if DEBUG
5656
|> Program.withDebugger
5757
#endif

Samples/SSRSample/src/Client/Client.fsproj

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,19 @@
33
<PropertyGroup>
44
<TargetFramework>netstandard2.0</TargetFramework>
55
</PropertyGroup>
6+
7+
<Import Project="../Shared/Shared.props" />
8+
69
<ItemGroup>
7-
<Compile Include="../../../../src/Fable.React/Fable.Import.React.fs" />
8-
<Compile Include="../../../../src/Fable.React/Fable.Helpers.React.fs" />
910
<!--
1011
Ensure elmish-react using the same fable-react,
1112
no need for production!
1213
-->
1314
<Compile Include="../../paket-files/fable-elmish/react/src/common.fs" />
1415
<Compile Include="../../paket-files/fable-elmish/react/src/react.fs" />
1516

16-
<Compile Include="..\Shared\Shared.fs" />
17-
<Compile Include="Types.fs" />
18-
<Compile Include="View.fs" />
1917
<Compile Include="Bench.fs" />
18+
<Compile Include="withReactHydrate.fs" />
2019
<Compile Include="Client.fs" />
2120
</ItemGroup>
2221
<Import Project="..\..\.paket\Paket.Restore.targets" />

Samples/SSRSample/src/Client/View.fs

Lines changed: 70 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,25 @@
22
module Client.View
33

44

5+
open Fable.Import
6+
open Fable.Core
7+
open Fable.Core.JsInterop
58
open Fable.Helpers.React
9+
open Fable.Helpers.Isomorphic
610
open Fable.Helpers.React.Props
711
open Client.Types
812
open Shared
913

14+
type [<Pojo>] JsCompProps = {
15+
text: string
16+
}
17+
18+
#if FABLE_COMPILER
19+
let JsComp: React.ComponentClass<JsCompProps> = importDefault "./jsComp"
20+
#else
21+
let JsComp = Unchecked.defaultof<React.ComponentClass<JsCompProps>>
22+
#endif
23+
1024
let show = function
1125
| Some x -> string x
1226
| None -> "Loading..."
@@ -32,6 +46,28 @@ let safeComponents =
3246
str " powered by: "
3347
components ]
3448

49+
let jsComp (props: JsCompProps) =
50+
ofImport "default" "./jsComp" props []
51+
52+
let jsCompServer (props: JsCompProps) =
53+
div [] [ str "loading" ]
54+
55+
type [<Pojo>] MyProp = {
56+
text: string
57+
}
58+
type [<Pojo>] MyState = {
59+
text: string
60+
}
61+
62+
type MyReactComp(initProps: MyProp) as self =
63+
inherit React.Component<MyProp, MyState>(initProps) with
64+
do self.setInitState { text="my state" }
65+
66+
override x.render() =
67+
div [] [ str (sprintf "prop: %s state: %s" x.props.text x.state.text) ]
68+
69+
70+
3571
let view (model: Model) (dispatch) =
3672
div []
3773
[ h1 [] [ str "SAFE Template" ]
@@ -65,28 +101,50 @@ let view (model: Model) (dispatch) =
65101
span [] [ str "Test checkbox:" ]
66102
input [ Type "checkbox"; DefaultChecked true ]
67103
input [ Type "checkbox"; DefaultChecked false ]
68-
input [ Type "checkbox"; Checked true ]
69-
input [ Type "checkbox"; Checked false ]
70-
input [ Type "checkbox"; Checked true; DefaultChecked false ]
71-
input [ Type "checkbox"; DefaultChecked true; Checked false ]
104+
input [ Type "checkbox"; Checked true; OnChange ignore ]
105+
input [ Type "checkbox"; Checked false; OnChange ignore ]
72106
]
73107
div [] [
74108
span [] [ str "Test value:" ]
75109
input [ Type "text"; DefaultValue "true" ]
76110
input [ Type "text"; DefaultValue "false" ]
77-
input [ Type "text"; Value "true" ]
78-
input [ Type "text"; Value "false" ]
79-
input [ Type "text"; Value "true"; DefaultValue "false" ]
80-
input [ Type "text"; DefaultValue "true"; Value "false" ]
111+
input [ Type "text"; Value "true"; OnChange ignore ]
112+
input [ Type "text"; Value "false"; OnChange ignore ]
81113
]
82114

83115
div [] [
84116
span [] [ str "Test textarea:" ]
85117
textarea [ DefaultValue "true" ] []
86118
textarea [ DefaultValue "false" ] []
87-
textarea [ Value "true" ] []
88-
textarea [ Value "false" ] []
89-
textarea [ Value "true"; DefaultValue "false" ] []
90-
textarea [ DefaultValue "true"; Value "false" ] []
119+
textarea [ Value "true"; OnChange ignore] []
120+
textarea [ Value "false"; OnChange ignore] []
91121
]
122+
123+
div [] [
124+
span [] [ str "Test React.Fragment:" ]
125+
fragment []
126+
[ span [] [ str "child 1" ]
127+
span [] [ str "child 2" ]
128+
span [] [ str "child 3" ]
129+
span [] [ str "child 4" ]
130+
]
131+
]
132+
133+
div [] [
134+
span [] [ str "Test escape:" ]
135+
fragment []
136+
[ span
137+
[ Data ("value", "<div>\"\'&</div>");
138+
Style [ Display "<div>\"\'&</div>"]
139+
]
140+
[ str "<div>\"\'&</div>" ]
141+
]
142+
]
143+
144+
div [] [
145+
span [] [ str "Test js component:" ]
146+
hybridView jsComp jsCompServer { text="I'm rendered by a js Component!" }
147+
]
148+
149+
ofType<MyReactComp, _, _> { text="my prop" } []
92150
]
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import React from 'react'
2+
3+
export default function JsComp({ text }) {
4+
return React.createElement('div', null, text)
5+
}
6+
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
namespace Client
2+
3+
open Elmish.React
4+
5+
[<RequireQualifiedAccess>]
6+
module Program =
7+
open Fable.Import.Browser
8+
let withReactHydrate placeholderId (program:Elmish.Program<_,_,_,_>) =
9+
let setState dispatch =
10+
let viewWithDispatch = program.view dispatch
11+
fun model ->
12+
Fable.Import.ReactDom.hydrate(
13+
lazyViewWith (fun x y -> obj.ReferenceEquals(x,y)) viewWithDispatch model,
14+
document.getElementById(placeholderId)
15+
)
16+
17+
{ program with setState = setState }

Samples/SSRSample/src/Server/Server.fs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ open System.Diagnostics
1919

2020
let clientPath = Path.Combine("..","Client") |> Path.GetFullPath
2121
let port = 8085us
22-
let assetsBaseUrl = "http://localhost:8082"
22+
let assetsBaseUrl = "http://localhost:8080"
2323

2424
let initState: Model = {
2525
counter = Some 42
@@ -50,7 +50,7 @@ let htmlTemplate =
5050
script []
5151
[ rawText (sprintf """
5252
var __INIT_STATE__ = %s
53-
""" (toJson (toJson initState))) ]
53+
""" (toJson (toJson initState))) ] // call toJson twice to output json as js string in html
5454
script [ _src (assetsBaseUrl + "/public/bundle.js") ] []
5555
]
5656
]

Samples/SSRSample/src/Server/Server.fsproj

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,9 @@
44
<OutputType>Exe</OutputType>
55
<TargetFramework>netcoreapp2.0</TargetFramework>
66
</PropertyGroup>
7+
<Import Project="../Shared/Shared.props" />
78
<ItemGroup>
8-
<Compile Include="../../../../src/Fable.React/Fable.Import.React.fs" />
9-
<Compile Include="../../../../src/Fable.React/Fable.Helpers.React.fs" />
109
<Compile Include="../../../../src/Fable.React/Fable.Helpers.ReactServer.fs" />
11-
<Compile Include="../Shared/Shared.fs" />
12-
<Compile Include="../Client/Types.fs" />
13-
<Compile Include="../Client/View.fs" />
1410
<Compile Include="./FableJson.fs" />
1511
<Compile Include="./Server.fs" />
1612
</ItemGroup>

0 commit comments

Comments
 (0)