This page covers Elm 0.18
合成
親コンポーネント
これは親コンポーネントのコードです。
module Main exposing (..)
import Html exposing (Html, program)
import Widget
-- モデル
type alias AppModel =
{ widgetModel : Widget.Model
}
initialModel : AppModel
initialModel =
{ widgetModel = Widget.initialModel
}
init : ( AppModel, Cmd Msg )
init =
( initialModel, Cmd.none )
-- メッセージ
type Msg
= WidgetMsg Widget.Msg
-- VIEW
view : AppModel -> Html Msg
view model =
Html.div []
[ Html.map WidgetMsg (Widget.view model.widgetModel)
]
-- 更新
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 : AppModel -> Sub Msg
subscriptions model =
Sub.none
-- APP
main : Program Never AppModel Msg
main =
program
{ init = init
, view = view
, update = update
, subscriptions = subscriptions
}
このコードの重要なセクションを見てみましょう。
モデル
type alias AppModel =
{ widgetModel : Widget.Model ➊
}
親コンポーネントには独自のモデルがあります。このモデルの属性の1つにWidget.Model
➊が含まれています。この親コンポーネントは Widget.Model
の中身を知る必要はないことに注意してください。
initialModel : AppModel
initialModel =
{ widgetModel = Widget.initialModel ➋
}
最初のアプリケーションモデルを作成するときは、単にここから Widget.initialModel
➋を呼び出します。
子コンポーネントが複数ある場合は、それぞれの子コンポーネントを同じように実行します。たとえば、次のようになります。
initialModel : AppModel
initialModel =
{ navModel = Nav.initialModel,
, sidebarModel = Sidebar.initialModel,
, widgetModel = Widget.initialModel
}
あるいは、同じタイプの複数の子コンポーネントを持つこともできます。
initialModel : AppModel
initialModel =
{ widgetModels = [Widget.initialModel]
}
メッセージ
type Msg
= WidgetMsg Widget.Msg
メッセージがそのコンポーネントに属していることを示すために Widget.Msg
をラップするユニオン型を使用します。これにより、アプリケーションが関連するコンポーネントにメッセージをルーティングできるようになります(これは、update関数を見ればより明確になります)。
複数の子コンポーネントを持つアプリケーションでは、次のようなものがあります。
type Msg
= NavMsg Nav.Msg
| SidebarMsg Sidebar.Msg
| WidgetMsg Widget.Msg
表示
view : AppModel -> Html Msg
view model =
Html.div []
[ Html.map➊ WidgetMsg➋ (Widget.view➌ model.widgetModel➍)
]
メインアプリケーションの view
はWidget.view
をレンダリングします。しかし、 Widget.view
はWidget.Msg
を送出するので、 Main.Msg
を送出するこのビューと互換性がありません。
Html.map
➊を使用して、放出されたメッセージをWidget.viewから期待されるタイプ(Msg)にマッピングします。Html.map
タグはWidgetMsg
タグを使ってサブビューから来るメッセージにタグを付けます。- 子コンポーネントが気にするモデルの部分、つまり
model.widgetModel
のみを渡します。
更新
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)
WidgetMsg
➊がupdate
によって受け取られると、子コンポーネントに更新を委譲します。しかし子コンポーネントは自分が担当するwidgetModel
属性だけを更新します。
パターンマッチングを使用して WidgetMsg
からsubMsg
➋を抽出します。この subMsg
はWidget.update
が予期する型になります。
この subMsg
とmodel.widgetModel
を使って、 Widget.update
➌を呼び出します。これは更新された widgetModel
とコマンドを含むタプルを返します。
Widget.update
からの応答を分解➍するためにパターンマッチングを使います。
最後に、 Widget.update
によって返されたコマンドを正しい型に対応付ける必要があります。このために Cmd.map
➎を使い、WidgetMsg
でコマンドにタグを付けます。これは、ビューで行ったのと同様です。