functional-programming - 如何与 Elm 中的多态子组件进行通信?
问题描述
我的主程序有一个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
需要以某种方式更改以与新的子组件一起使用。
如何统一这两种类型并使两个组件一起工作?
解决方案
我认为问题在于您在公开Msg
类型中泄露了太多信息。您对 type 参数的使用Msg a
似乎仅限于一组已知类型,即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)
推荐阅读
- python - 如何按特定顺序搜索字符串中的项目
- javascript - PDFKit Node.js 测量单位
- reactjs - 为一些 Redux 状态更改添加 url 路由
- javascript - Griddle,将 2 个变量传递给自定义组件
- r - 模拟 6 个特征的 beta 分布
- javascript - 在页面加载 Javascript 上选择默认单选输入
- regex - 用于仅提取 Angular 5 中的 Youtube 嵌入 URL 的正则表达式
- vue.js - "background-image:url("+bg+")" ,+ 符号是什么?Vue.js
- c++ - C++ 中的抽象硬件依赖关系
- google-apps-script - 条件格式