в общем, все эльмийские «компоненты» (вы можете понимать это как «файл») имеют:
- a
Model
, представляющее их состояние - a
Msg
представление возможного действия, поддерживаемого в компоненте - и функции
update
, реагирующей на Msg
и генерирующей новый Model
из предыдущего состояния Model
- a
view
для генерации представления из текущего Model
состояния
В моем приложении я использую следующую структуру, которая позволяет мне масштабировать (бесконечно) приложение.
A Router.fs
файл, отвечающий за обработку, представляет различные маршруты и функцию parsing
.
let inline (</>) a b = a + "/" + string b
type Route =
| Home
| Blog of int
let toHash (route : Route) =
match route with
| Home -> "home"
| Blog id -> "blog" </> id
open Elmish.Browser.Navigation
open Elmish.Browser.UrlParser
let routeParser : Parser<Route -> Route, Route> =
oneOf [ // Auth Routes
map (fun domainId -> Route.Blog domainId) (s "blog" </> i32)
map Route.Home (s "home")
// Default Route
map Route.Home top ]
A Main.fs
файл, отвечающий за создание программы Elmish и обработку реакции на изменения маршрута.
open Elmish
open Fable.Helpers.React
open Fable.Import
type Page =
| Home of Home.Model
| Blog of Blog.Model
| NotFound
type Model =
{ ActivePage : Page
CurrentRoute : Router.Route option }
type Msg =
| HomeMsg of Home.Msg
| BlogMsg of Blog.Msg
let private setRoute (optRoute: Router.Route option) model =
let model = { model with CurrentRoute = optRoute }
match optRoute with
| None ->
{ model with ActivePage = Page.NotFound }, Cmd.none
| Some Router.Route.Home ->
let (homeModel, homeCmd) = Home.init ()
{ model with ActivePage = Page.Home homeModel }, Cmd.map HomeMsg homeCmd
| Some (Router.Route.Blog blogId) ->
let (blogModel, blogCmd) = Blog.init blogId
{ model with ActivePage = Page.Blog blogModel }, Cmd.map BlogMsg blogCmd
let init (location : Router.Route option) =
setRoute location
{ ActivePage = Page.NotFound
CurrentRoute = None }
let update (msg : Msg) (model : Model) =
match model.ActivePage, msg with
| Page.NotFound, _ ->
// Nothing to do here
model, Cmd.none
| Page.Home homeModel, HomeMsg homeMsg ->
let (homeModel, homeCmd) = Home.update homeMsg homeModel
{ model with ActivePage = Page.Home homeModel }, Cmd.map HomeMsg homeCmd
| Page.Blog blogModel, BlogMsg blogMsg ->
let (blogModel, blogCmd) = Blog.update blogMsg blogModel
{ model with ActivePage = Page.Blog blogModel }, Cmd.map BlogMsg blogCmd
| _, msg ->
Browser.console.warn("Message discarded:\n", string msg)
model, Cmd.none
let view (model : Model) (dispatch : Dispatch<Msg>) =
match model.ActivePage with
| Page.NotFound ->
str "404 Page not found"
| Page.Home homeModel ->
Home.view homeModel (HomeMsg >> dispatch)
| Page.Blog blogModel ->
Blog.view blogModel (BlogMsg >> dispatch)
open Elmish.Browser.UrlParser
open Elmish.Browser.Navigation
open Elmish.React
// App
Program.mkProgram init update view
|> Program.toNavigable (parseHash Router.routeParser) setRoute
|> Program.withReactUnoptimized "elmish-app"
|> Program.run
Так что в вашем случае у меня были бы следующие файлы:
Router.fs
Home.fs
Blog.fs
Main.fs