如何与 Elm 中的多态 child 组件通信?
How to communicate with a polymorphic child component in Elm?
我的主程序有一个update
函数
update : Msg -> Model -> ( Model, Cmd Msg )
要与 sub-components 通信,我们可以添加另一个变体并将我们的消息包装在新消息中
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 )
然而,如果我的 sub-component 的 update
函数的类型与 parent 不匹配,这似乎具有挑战性。考虑具有多态更新函数的 child:
-- 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
的函数都需要以某种方式进行更改以与新的 child 组件一起使用。
如何统一这两种类型并使这两个组件协同工作?
我认为问题是您在 publicly 公开的 Msg
类型中泄露了太多信息。您对 Msg a
类型参数的使用似乎仅限于一组已知类型,Author
、Category
、Post
或 Tag
。从浏览你的代码来看,它似乎永远只是这四个之一,所以你以这种方式抽象事物的事实应该保留在这个模块内部,而不是暴露它并给任何其他可能拉动的代码增加负担这个在.
我认为您需要将抽象下移一个级别以避免参数化您的 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)
我的主程序有一个update
函数
update : Msg -> Model -> ( Model, Cmd Msg )
要与 sub-components 通信,我们可以添加另一个变体并将我们的消息包装在新消息中
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 )
然而,如果我的 sub-component 的 update
函数的类型与 parent 不匹配,这似乎具有挑战性。考虑具有多态更新函数的 child:
-- 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
的函数都需要以某种方式进行更改以与新的 child 组件一起使用。
如何统一这两种类型并使这两个组件协同工作?
我认为问题是您在 publicly 公开的 Msg
类型中泄露了太多信息。您对 Msg a
类型参数的使用似乎仅限于一组已知类型,Author
、Category
、Post
或 Tag
。从浏览你的代码来看,它似乎永远只是这四个之一,所以你以这种方式抽象事物的事实应该保留在这个模块内部,而不是暴露它并给任何其他可能拉动的代码增加负担这个在.
我认为您需要将抽象下移一个级别以避免参数化您的 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)