我的主程序具有update
功能
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
的每个函数,以便与新的子组件一起使用。
如何统一这两种类型并使两个组件一起工作?
答案 0 :(得分:3)
我认为问题在于,您在公开公开的Msg
类型中泄漏了太多信息。您对Msg a
的type参数的使用似乎仅限于一组已知的类型,即Author
,Category
,Post
或Tag
。从略读代码来看,看起来将永远只是这四个代码之一,因此,您应将以这种方式抽象化的事实保存在该模块内部,而不是公开它并负担任何其他可能拉扯的代码这个。
我认为您需要将抽象向下移动,以避免参数化您的公共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)