You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/recipes/ui/routing-with-elmish.md
+91-82Lines changed: 91 additions & 82 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -8,40 +8,17 @@ In this recipe we add routing to a safe app, and implement the todo list page us
8
8
9
9
## 1. Installing dependencies
10
10
11
-
!!! warning "Pin Fable.Core to V3"
12
-
At the time of writing, the published version of the SAFE template does not have the version of `Fable.Core` pinned; this can create problems when installing dependencies.
13
-
14
-
If you are using version v.4.2.0 of the template, pin `Fable.Core` to version 3 in `paket.depedencies` at the root of the project
15
-
16
-
```.diff title="paket.dependencies"
17
-
...
18
-
-nuget Fable.Core
19
-
+nuget Fable.Core ~> 3
20
-
...
21
-
```
22
-
23
-
24
11
Install Feliz.Router in the Client project
25
12
26
13
```bash
27
-
dotnet paket add Feliz.Router -p Client -V 3.8
14
+
dotnet paket add Feliz.Router -p Client
28
15
```
29
16
30
-
!!! Warning "Feliz.Router versions"
31
-
At the time of writing, the current version of the SAFE template (4.2.0) does not work well with the latest version of Feliz.Router (4.0).
32
-
To work around this, we install Feliz.Router 3.8, the latest version that works with SAFE template version 4.2.0.
33
-
34
-
If you are working with a newer version of the SAFE template, it might be worth trying to install the newest version of Feliz.Router.
35
-
To see the installed version of the SAFE template, run in the command line:
36
-
37
-
```bash
38
-
dotnet new --list
39
-
```
40
-
41
17
Install Feliz.UseElmish in the Client project
42
18
43
19
```bash
44
-
dotnet paket add Feliz.UseElmish -p client
20
+
cd src/Client
21
+
dotnet femto install Feliz.UseElmish
45
22
```
46
23
47
24
Open the router in the client project
@@ -58,10 +35,10 @@ Create a new Module `TodoList` in the client project. Move the following functio
58
35
* Msg
59
36
* todosApi
60
37
* init
61
-
*update
62
-
*containerBox
38
+
*todoAction
39
+
*todoList
63
40
64
-
Also open `Shared`, `Fable.Remoting.Client`, `Elmish`, `Feliz.Bulma` and `Feliz`.
41
+
Also open `Shared`, `Fable.Remoting.Client`, `Elmish` and `Feliz`.
65
42
66
43
```fsharp title="TodoList.fs"
67
44
module TodoList
@@ -70,7 +47,6 @@ open Shared
70
47
open Fable.Remoting.Client
71
48
open Elmish
72
49
73
-
open Feliz.Bulma
74
50
open Feliz
75
51
76
52
type Model = { Todos: Todo list; Input: string }
@@ -86,13 +62,12 @@ let todosApi =
86
62
|> Remoting.withRouteBuilder Route.builder
87
63
|> Remoting.buildProxy<ITodosApi>
88
64
89
-
let init () : Model * Cmd<Msg> =
65
+
let init () =
90
66
let model = { Todos = []; Input = "" }
91
67
let cmd = Cmd.OfAsync.perform todosApi.getTodos () GotTodos
92
-
93
68
model, cmd
94
69
95
-
let update (msg: Msg) (model: Model) : Model * Cmd<Msg> =
70
+
let update msgmodel =
96
71
match msg with
97
72
| GotTodos todos -> { model with Todos = todos }, Cmd.none
98
73
| SetInput value -> { model with Input = value }, Cmd.none
@@ -102,43 +77,57 @@ let update (msg: Msg) (model: Model) : Model * Cmd<Msg> =
102
77
let cmd = Cmd.OfAsync.perform todosApi.addTodo todo AddedTodo
103
78
104
79
{ model with Input = "" }, cmd
105
-
| AddedTodo todo -> { model with Todos = model.Todos @ [ todo ] }, Cmd.none
106
-
107
-
let containerBox (model: Model) (dispatch: Msg -> unit) =
+ let model, dispatch = React.useElmish(init, update, [||])
151
+
-let containerBox modeldispatch =
152
+
+let view modeldispatch =
153
+
+ let model, dispatch = React.useElmish(init, update, [||])
165
154
...
166
155
```
167
156
@@ -176,7 +165,7 @@ Replace the arguments of the function with unit, and add the `ReactComponent` at
176
165
=== "Diff"
177
166
```.diff title="Index.fs"
178
167
+ [<ReactComponent>]
179
-
- let view (model: Model) (dispatch: Msg -> unit) =
168
+
- let view modeldispatch =
180
169
+ let view () =
181
170
...
182
171
```
@@ -213,9 +202,7 @@ let initFromUrl url =
213
202
Create a new `init` function, that fetches the current url, and calls initFromUrl.
214
203
215
204
```fsharp title="Index.fs"
216
-
let init () =
217
-
Router.currentUrl ()
218
-
|> initFromUrl
205
+
let init () = Router.currentUrl () |> initFromUrl
219
206
```
220
207
## 7. Updating the Page
221
208
@@ -228,33 +215,55 @@ type Msg =
228
215
Add an `update` function, that reinitializes the app based on an URL
229
216
230
217
```fsharp title="Index.fs"
231
-
let update (msg: Msg) (model: Model) : Model * Cmd<Msg> =
218
+
let update msgmodel =
232
219
match msg with
233
-
| PageChanged url ->
234
-
initFromUrl url
220
+
| PageChanged url -> initFromUrl url
235
221
```
236
222
237
223
## 8. Displaying pages
238
224
239
-
Add a containerBox function to the `Index` module, that returns the appropriate page content
225
+
Add a pageContent function to the `Index` module, that returns the appropriate page content
240
226
241
227
```fsharp title="Index.fs"
242
-
let containerBox (model: Model) (dispatch: Msg -> unit) =
228
+
let pageContent model =
243
229
match model.CurrentPage with
244
-
| NotFound -> Bulma.box "Page not found"
230
+
| NotFound -> Html.text "Page not found"
245
231
| TodoList -> TodoList.view ()
246
232
```
233
+
234
+
In the `view` function, replace the call to `todoList` with a call to `pageContent`
235
+
236
+
=== "Code"
237
+
```
238
+
let view model dispatch =
239
+
Html.section [
240
+
...
241
+
pageContent model
242
+
...
243
+
]
244
+
```
245
+
=== "Diff"
246
+
```
247
+
let view model dispatch =
248
+
Html.section [
249
+
...
250
+
- todoList view model
251
+
+ pageContent model
252
+
...
253
+
]
254
+
```
255
+
247
256
## 9. Add the router to the view
248
257
249
258
Wrap the content of the view method in a `React.Router` element's router.children property, and add a `router.onUrlChanged` property to dispatch the urlChanged message
250
259
251
260
=== "Code"
252
261
```fsharp title="Index.fs"
253
-
let view (model: Model) (dispatch: Msg -> unit) =
262
+
let view modeldispatch =
254
263
React.router [
255
264
router.onUrlChanged ( PageChanged>>dispatch )
256
265
router.children [
257
-
Bulma.hero[
266
+
Html.section[
258
267
...
259
268
]
260
269
]
@@ -266,7 +275,7 @@ Wrap the content of the view method in a `React.Router` element's router.childre
0 commit comments