Elm 中组件之间的通信
communication between components in Elm
假设我正在尝试遵循 Elm 架构并将我的工作流程拆分为 User
s 和 Invoice
s,同时使用 StartApp
.
用户有发票,但他们必须登录才能访问。
该模型可能看起来像这样:
type Model
= NotLoggedIn Credentials
| LoggedIn RealName (Maybe Invoices)
type alias State =
{ login : Model
, notification : ......
, ......
type alias Invoices = { invoices: List Invoice, ...... }
用户模块有动作:
type Action
= Login (Result Http.Error String)
| Logout
| Submit
...
和更新功能:
update : Action -> Model -> (Model, Effects Action, Notification)
update action user =
case (action, user) of
(Login res, _) ->
case res of
Ok name ->
(LoggedIn name Nothing, Effects.none, Info "Welcome!")
...
我跳过身份验证的细节,一切都很好。有趣的部分是 Login
动作。元组被发送到 main
:
中的 step
函数
step : Action -> State -> (State, Effects Action)
step action state =
case action of
UserAction a ->
let (newstate, ef, n) = User.update a state.login
in ({ state | login = newstate, notification = n }, Effects.map UserAction ef)
InvoiceAction a -> ......
所以用户已经登录。接下来我们要在 Invoice
模块中调用一些 init
操作。
但这应该如何正确完成呢?如何发起Invoice
的动作来保持封装?我可以 return 除了 Effects.none
以外的其他东西吗?
一种方法是:
- 在父组件中创建邮箱
- 将该邮箱的地址传递给
User
更新
- 用户更新returns一个发送消息到这个地址的效果
- 收到邮件后,此邮箱会触发流向
Invoice
的操作
elm-tutorial 中的这一章显示了这种模式。
这种情况可能可以通过对您的应用数据进行不同建模来解决。
据我了解,您有需要作为用户的操作和不需要用户的操作。 InvoiceAction 在我看来应该属于 UserAction。
所以,你可以
type MainAction = UserAction UAction | NonUserAction NonUAction
type UAction = AuthAction Credentials | InvoiceAction Invoice.Action
用户模型将封装登录详细信息和发票详细信息。然后,在成功登录后,您可以重定向到 InvoiceAction。
update action model =
case action of
AuthAction credentials ->
let
(isLoggedIn, notifications) = Authentication.check credentials
model' = { model | credentials = credentials, notifications = notifications}
in
if isLoggedIn
then update (Invoice.initialize model'.credentials) model'
else (model', Effects.none)
InvoiceAction act ->
let
(invoices, fx) = Invoice.update model.credentials act model.invoices
in
({model | invoices = invoices}, Effects.map InvoiceAction fx)
实际操作由 Invoice 模块通过函数 initialize
提供,签名如 initialize: Credentials -> Action
。这样做是为了保持封装。用户模块不需要知道特定的发票操作,只需要知道一个与初始化相关的操作,它可以通过该函数获取它。
另外,请注意我简化了更新签名并将通知移到了模型中。这是个人偏好,因为我认为通知没什么特别的。它们就像模型中的任何其他数据一样。当然,如果通知是通过某些自定义 StartApp 路由到端口并通过某些 JS 机制显示的任务,将它们保留在 return 中可能是有意义的。
假设我正在尝试遵循 Elm 架构并将我的工作流程拆分为 User
s 和 Invoice
s,同时使用 StartApp
.
用户有发票,但他们必须登录才能访问。
该模型可能看起来像这样:
type Model
= NotLoggedIn Credentials
| LoggedIn RealName (Maybe Invoices)
type alias State =
{ login : Model
, notification : ......
, ......
type alias Invoices = { invoices: List Invoice, ...... }
用户模块有动作:
type Action
= Login (Result Http.Error String)
| Logout
| Submit
...
和更新功能:
update : Action -> Model -> (Model, Effects Action, Notification)
update action user =
case (action, user) of
(Login res, _) ->
case res of
Ok name ->
(LoggedIn name Nothing, Effects.none, Info "Welcome!")
...
我跳过身份验证的细节,一切都很好。有趣的部分是 Login
动作。元组被发送到 main
:
step
函数
step : Action -> State -> (State, Effects Action)
step action state =
case action of
UserAction a ->
let (newstate, ef, n) = User.update a state.login
in ({ state | login = newstate, notification = n }, Effects.map UserAction ef)
InvoiceAction a -> ......
所以用户已经登录。接下来我们要在 Invoice
模块中调用一些 init
操作。
但这应该如何正确完成呢?如何发起Invoice
的动作来保持封装?我可以 return 除了 Effects.none
以外的其他东西吗?
一种方法是:
- 在父组件中创建邮箱
- 将该邮箱的地址传递给
User
更新 - 用户更新returns一个发送消息到这个地址的效果
- 收到邮件后,此邮箱会触发流向
Invoice
的操作
elm-tutorial 中的这一章显示了这种模式。
这种情况可能可以通过对您的应用数据进行不同建模来解决。
据我了解,您有需要作为用户的操作和不需要用户的操作。 InvoiceAction 在我看来应该属于 UserAction。
所以,你可以
type MainAction = UserAction UAction | NonUserAction NonUAction
type UAction = AuthAction Credentials | InvoiceAction Invoice.Action
用户模型将封装登录详细信息和发票详细信息。然后,在成功登录后,您可以重定向到 InvoiceAction。
update action model =
case action of
AuthAction credentials ->
let
(isLoggedIn, notifications) = Authentication.check credentials
model' = { model | credentials = credentials, notifications = notifications}
in
if isLoggedIn
then update (Invoice.initialize model'.credentials) model'
else (model', Effects.none)
InvoiceAction act ->
let
(invoices, fx) = Invoice.update model.credentials act model.invoices
in
({model | invoices = invoices}, Effects.map InvoiceAction fx)
实际操作由 Invoice 模块通过函数 initialize
提供,签名如 initialize: Credentials -> Action
。这样做是为了保持封装。用户模块不需要知道特定的发票操作,只需要知道一个与初始化相关的操作,它可以通过该函数获取它。
另外,请注意我简化了更新签名并将通知移到了模型中。这是个人偏好,因为我认为通知没什么特别的。它们就像模型中的任何其他数据一样。当然,如果通知是通过某些自定义 StartApp 路由到端口并通过某些 JS 机制显示的任务,将它们保留在 return 中可能是有意义的。