Cette page couvre Elm 0.18

Composition

Le composant parent

Voici le code du composant parent :

module Main exposing (..)

import Html exposing (Html, program)
import Widget


-- MODEL


type alias AppModel =
    { widgetModel : Widget.Model
    }


initialModel : AppModel
initialModel =
    { widgetModel = Widget.initialModel
    }


init : ( AppModel, Cmd Msg )
init =
    ( initialModel, Cmd.none )



-- MESSAGES


type Msg
    = WidgetMsg Widget.Msg



-- VIEW


view : AppModel -> Html Msg
view model =
    Html.div []
        [ Html.map WidgetMsg (Widget.view model.widgetModel)
        ]



-- UPDATE


update : Msg -> AppModel -> ( AppModel, Cmd Msg )
update message model =
    case message of
        WidgetMsg subMsg ->
            let
                ( updatedWidgetModel, widgetCmd ) =
                    Widget.update subMsg model.widgetModel
            in
                ( { model | widgetModel = updatedWidgetModel }, Cmd.map WidgetMsg widgetCmd )



-- SUBSCRIPTIONS


subscriptions : AppModel -> Sub Msg
subscriptions model =
    Sub.none



-- APP


main : Program Never AppModel Msg
main =
    program
        { init = init
        , view = view
        , update = update
        , subscriptions = subscriptions
        }

Passons en revue les parties importantes de ce code.

Modèle

type alias AppModel =
    { widgetModel : Widget.Model ➊
    }

Le composant parent a son propre modèle. Un des attributs de ce modèle contient Widget.Model ➊. Notez que le composant parent n'a pas besoin de savoir ce que Widget.Model est.

initialModel : AppModel
initialModel =
    { widgetModel = Widget.initialModel ➋
    }

Lorsque nous créons le modèle initial de notre application, nous appelons simplement Widget.initialModel ➋.

Si vous aviez à gérer plusieurs composants enfants, vous feriez de même pour chaque, à savoir :

initialModel : AppModel
initialModel =
    { navModel = Nav.initialModel,
    , sidebarModel = Sidebar.initialModel,
    , widgetModel = Widget.initialModel
    }

Ou nous pourrions aussi avoir de multiples composants enfants du même type :

initialModel : AppModel
initialModel =
    { widgetModels = [Widget.initialModel]
    }

Messages

type Msg
    = WidgetMsg Widget.Msg

Nous utilisons un type d'union qui encapsule Widget.Msg pour indique que ce message appartient à ce composant. Cela permet à notre application de diriger les messages vers les bons composants (ça sera plus clair lorsque que nous verrons la fonction update).

Dans une application avec de multiples composants enfants, nous pourrions avoir quelque chose de ce type :

type Msg
    = NavMsg Nav.Msg
    | SidebarMsg Sidebar.Msg
    | WidgetMsg Widget.Msg

Vue

view : AppModel -> Html Msg
view model =
    Html.div []
        [ Html.map➊ WidgetMsg➋ (Widget.view➌ model.widgetModel➍)
        ]

La fonction view de l'application affiche Widget.view ➌. Mais Widget.view émet des messages de type Widget.Msg qui ne sont pas compatibles avec cette vue, qui elle émet des messages du type Main.Msg.

  • Nous utilisons Html.map ➊ pour transformer les messages émis de Widget.view vers le type que nous attendons (Msg). Html.map étiquette les messages venant de la sous-vue en utilisant l'étiquette WidgetMsg ➋.
  • Nous passons uniquement la partie du modèle qui concerne le composant enfant, à savoir model.widgetModel ➍.

Mise à jour

update : Msg -> AppModel -> (AppModel, Cmd Msg)
update message model =
    case message of
        WidgetMsg➊ subMsg➋ ->
            let
                (updatedWidgetModel, widgetCmd)➍ =
                    Widget.update➌ subMsg model.widgetModel
            in
                ({ model | widgetModel = updatedWidgetModel }, Cmd.map➎ WidgetMsg widgetCmd)

Lorsqu'un WidgetMsg ➊ est reçu par update, nous déléguons la mise à jour au composant enfant. Mais le composant enfant ne mettra à jour que ce qui l'intéresse, c'est à dire l'attribut widgetModel de notre modèle.

Nous utilisons du pattern matching pour extraire le subMsg ➋ de WidgetMsg. Ce subMsg sera du type que Widget.update attend.

Nous appelons Widget.update ➌ en utilisant notre subMsg et notre model.widgetModel. Cela va nous retourner un tuple avec un widgetModel mis à jour et une commande.

Nous utilisons de nouveau le pattern matching pour déconstruire ➍ la réponse de Widget.update.

Enfin, nous avons besoin de faire correspondre la commande retournée par Widget.update au type adéquat. Pour ce faire nous utilisons Cmd.map ➎ et nous étiquetons la commande avec WidgetMsg, de la même manière que pour la vue.

results matching ""

    No results matching ""