我的主程序有一个更新
功能
update : Msg -> Model -> ( Model, Cmd Msg )
为了与子组件通信,我们可以添加另一个变体并将消息包装在新消息中
type alias Model =
{ ...
, child : Child.Model
}
type Msg
= ...
| ChildMsg Child.Msg
update msg model =
case msg of
...
ChildMsg childMsg ->
let
( childModel, cmd ) =
Child.update childMsg model.child
updatedModel =
{ model | child = childModel }
childCmd =
Cmd.map ChildMsg cmd
in
( updatedModel, childCmd )
但是,如果我的子组件的 update
函数的类型与父组件不匹配,这似乎具有挑战性。考虑一个具有多态更新函数的子进程:
-- PolymorphicChild.elm
update : Msg a -> Model -> ( Model, Cmd (Msg a) )
从此模块运行命令时,我必须将其包装
PolymorphicChild.someCommand : Cmd (Msg Foo)
PolymorphicChild.someCommand
|> Cmd.map PolymorphicChild
但是,这会产生 Msg (PolymorphicChild.Msg Foo)
,而不是我的应用程序期望的 Msg PolymorphicChild.Msg
。
The right side of (|>) is causing a type mismatch.
(|>) is expecting the right side to be a:
Cmd (PolyMorphicChild.Msg Foo) -> a
But the right side is:
Cmd Polymorphic.Msg -> Cmd Msg
我尝试向 App.Msg
添加多态参数
-- App.elm
type Msg a =
= ..
| PolymorphicChildMsg (PolymorphicChild.Msg a)
但这基本上毁掉了我的整个程序。每个涉及 App.Msg
的函数都需要以某种方式进行更改才能与新的子组件一起使用。
如何统一这两种类型并使这两个组件协同工作?
最佳答案
我认为问题在于您在公开的 Msg
类型中泄露了太多信息。您对 Msg a
类型参数的使用似乎仅限于一组已知的类型,例如 Author
、Category
、Post
或标签
。从浏览你的代码来看,它看起来永远不会只是这四种之一,因此你以这种方式抽象事物的事实应该保留在这个模块内部,而不是暴露它并给可能拉动的任何其他代码带来负担。这个在。
我认为您需要将抽象降低一个级别,以避免参数化您的公共(public) Msg
类型。我建议为 Msg
使用四个具体的构造函数,而不是对其进行参数化,并将抽象转移到帮助器 LoadInfo a
类型:
type alias LoadInfo a =
{ worker : Worker a
, url : Url
, result : Result Http.Error ( Int, List a )
}
type Msg
= LoadPost (LoadInfo Post)
| LoadCategory (LoadInfo Category)
| LoadTag (LoadInfo Tag)
| LoadAuthor (LoadInfo Author)
关于functional-programming - 如何与 Elm 中的多态子组件通信?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51199458/