Communication between components in Elm

Let's say I try to follow the Elm architecture and break my workflow into Userand out Invoiceof use StartApp.

Users have invoices, but they must be logged in to access them.

A model might look something like this:

type Model
   = NotLoggedIn Credentials
   | LoggedIn RealName (Maybe Invoices)

type alias State =
   { login : Model
   , notification : ......
   , ......


type alias Invoices = { invoices: List Invoice, ...... }

The user module has actions:

type Action
   = Login (Result Http.Error String)
   | Logout
   | Submit
   ...

and update function:

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!")
   ...

I will skip authentication details, all is well. The interesting part is the action Login. The tuple is sent to the function stepin main:

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 -> ......

So, the user is logged in. Then we want to call some action initin the module Invoice.

But how should this be done correctly? How to initiate an action Invoiceto preserve encapsulation? Should I return except Effects.none?

+4
2

, .

, , , . 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)

- initialize initialize: Credentials -> Action. . , , , .

, . , . . , - , - StartApp - JS, .

+3
+2

All Articles