F# SAFE 如何处理消息 DU 变体的增长?
F# SAFE how to deal with growth of message DU variants?
在 F# SAFE 堆栈中有一个 DU 类型,它定义了在服务器和客户端之间流动的所有类型的消息。在示例应用程序中,有 <10 个,我查看了提供的示例 - 所有这些都没有很多可能的类型。但是如果应用程序不小怎么办——DU 中会有数百种类型;这将变得难以维护。所以我决定把这个类型分成子类型,把逻辑放在相应的文件中。
这是我的简化类型:
type Msg2 =
| LoginMsg of LoginState
| RegisterMsg of RegisterState
| ViewUpdateMsg of ViewUpdateState
登录状态在另一个文件中定义:
type LoginState =
| Login
| LogInResult of LoginResult
登录模块与登录一起工作:
let workWithLogin (model: Model) (msg: LoginState) (todosApi: ITodosApi) : Model * Cmd<LoginState> =
match msg with
| LoginState.Login ->
let result =
Cmd.OfAsync.perform todosApi.login model.InputData LoginState.LogInResult
model, result
| LoginState.LogInResult data ->
{ model with
LoginState = getVal data.Message
Token = data.Token },
Cmd.none
注意它 returns Model * Cmd<LoginState>
.
现在我需要修复我的更新功能:
let update2 (msg: Msg2) (model: Model) : Model * Cmd<Msg2> =
match msg with
| LoginMsg n ->
let ret = workWithLogin model n todosApi
model, snd ret
| RegisterMsg n -> ...
| ViewUpdateMsg n -> ...
这里的问题是我从登录模块获取 Cmd<LoginState>
并且需要以某种方式将其转换为 Cmd<Msg2>
。
所以我要么需要创建新的 Msg2
类型,要么将 DU 变体 LoginMsg of LoginState
转换为 Msg2
。我不明白如何从 Cmd<LoginState>
.
获取 LogInResult
数据
我该如何解决这个问题?大项目中消息类型多的问题是如何解决的?
您在“子”消息中所做的包装是正确的方法,您可能应该对模型做同样的事情 - 即让 Login
拥有自己的模型。要在不同的 Cmd<'msg>
之间转换,有一个 Cmd.map
。在您的情况下,您可以:
let update2 (msg: Msg2) (model: Model) : Model * Cmd<Msg2> =
match msg with
| LoginMsg n ->
let (loginModel, loginCmd) = workWithLogin model n todosApi
{ model with Login = loginModel }, Cmd.map LoginMsg loginCmd
您可以在此处查看 Cmd
的一些 API 描述:https://elmish.github.io/elmish/cmd.html
在 F# SAFE 堆栈中有一个 DU 类型,它定义了在服务器和客户端之间流动的所有类型的消息。在示例应用程序中,有 <10 个,我查看了提供的示例 - 所有这些都没有很多可能的类型。但是如果应用程序不小怎么办——DU 中会有数百种类型;这将变得难以维护。所以我决定把这个类型分成子类型,把逻辑放在相应的文件中。
这是我的简化类型:
type Msg2 =
| LoginMsg of LoginState
| RegisterMsg of RegisterState
| ViewUpdateMsg of ViewUpdateState
登录状态在另一个文件中定义:
type LoginState =
| Login
| LogInResult of LoginResult
登录模块与登录一起工作:
let workWithLogin (model: Model) (msg: LoginState) (todosApi: ITodosApi) : Model * Cmd<LoginState> =
match msg with
| LoginState.Login ->
let result =
Cmd.OfAsync.perform todosApi.login model.InputData LoginState.LogInResult
model, result
| LoginState.LogInResult data ->
{ model with
LoginState = getVal data.Message
Token = data.Token },
Cmd.none
注意它 returns Model * Cmd<LoginState>
.
现在我需要修复我的更新功能:
let update2 (msg: Msg2) (model: Model) : Model * Cmd<Msg2> =
match msg with
| LoginMsg n ->
let ret = workWithLogin model n todosApi
model, snd ret
| RegisterMsg n -> ...
| ViewUpdateMsg n -> ...
这里的问题是我从登录模块获取 Cmd<LoginState>
并且需要以某种方式将其转换为 Cmd<Msg2>
。
Msg2
类型,要么将 DU 变体 LoginMsg of LoginState
转换为 Msg2
。我不明白如何从 Cmd<LoginState>
.
LogInResult
数据
我该如何解决这个问题?大项目中消息类型多的问题是如何解决的?
您在“子”消息中所做的包装是正确的方法,您可能应该对模型做同样的事情 - 即让 Login
拥有自己的模型。要在不同的 Cmd<'msg>
之间转换,有一个 Cmd.map
。在您的情况下,您可以:
let update2 (msg: Msg2) (model: Model) : Model * Cmd<Msg2> =
match msg with
| LoginMsg n ->
let (loginModel, loginCmd) = workWithLogin model n todosApi
{ model with Login = loginModel }, Cmd.map LoginMsg loginCmd
您可以在此处查看 Cmd
的一些 API 描述:https://elmish.github.io/elmish/cmd.html