2

在 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

请注意,它返回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 LoginStateMsg2. 我不明白如何从中获取LogInResult数据Cmd<LoginState>

我怎样才能解决这个问题?大型项目中如何解决消息类型多的问题?

4

1 回答 1

2

你用“子”消息包装所做的事情是正确的方法,你可能应该对模型做同样的事情 - 即让它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

你可以在这里看到一些 API 描述Cmdhttps ://elmish.github.io/elmish/cmd.html

于 2021-08-06T07:29:56.333 回答