Elm --- 階層化
下記記事にてElmを用いてカウンタを実装しました。
Elm --- Model、View、Update - 何でもプログラミング
今回はこのカウンタを再利用して、複数のカウンタを配置してみます。
内容はElmのTutorialにあるものとほとんど同じです。
作成するアプリケーション
カウンタが2つあり、一番下に合計値が出力されるアプリケーションになります。
Counter.elm
新たにCounter.elmファイルを作成し、下記コードを記述します。
内容は上記記事のものとほぼ同じです。
VisualStudioCodeを利用しているのですが、関数の型宣言をしないと警告が出るようになっていました。
module Counter exposing (..) import Html exposing (Html, div, button, text) import Html.Events exposing (onClick) type alias Model = { count : Int } initialModel : Model initialModel = { count = 0 } type Msg = Increment | Decrement update : Msg -> Model -> Model update msg model = case msg of Increment -> { model | count = model.count + 1 } Decrement -> { model | count = model.count - 1 } view : Model -> Html Msg view model = div [] [ button [ onClick Decrement ] [ text "-" ] , div [] [ text (toString model.count) ] , button [ onClick Increment ] [ text "+" ] ]
Main.elm
CounterのModel、update、viewをそのまま利用しています。
Html.App.mapを利用して、CounterのメッセージをMainの方に伝搬しています。
beginnerProgramがいつの間にかHtml.Appに移動していました。
import Html exposing (Html, div, text) import Html.App exposing (beginnerProgram, map) import Counter type alias Model = { counter1 : Counter.Model , counter2 : Counter.Model } initialModel : Model initialModel = { counter1 = Counter.initialModel , counter2 = Counter.initialModel } type Msg = Counter1Msg Counter.Msg | Counter2Msg Counter.Msg update : Msg -> Model -> Model update msg model = case msg of Counter1Msg x -> { model | counter1 = Counter.update x model.counter1 } Counter2Msg x -> { model | counter2 = Counter.update x model.counter2 } view : Model -> Html Msg view model = div [] [ map Counter1Msg (Counter.view model.counter1) , map Counter2Msg (Counter.view model.counter2) , div [] [ text (toString (model.counter1.count + model.counter2.count)) ] ] main : Program Never main = beginnerProgram { model = initialModel , view = view , update = update }
主要部分
// CounterのModelを保持 type alias Model = { counter1 : Counter.Model // メッセージの一つをCounterのMsg型に type Msg = Counter1Msg Counter.Msg // CounterのMsg型が来たらCounterのupdateを実行 update msg model = case msg of Counter1Msg x -> { model | counter1 = Counter.update x model.counter1 } // Counterのviewを利用し、mapにてメッセージを受け取り view model = div [] [ map Counter1Msg (Counter.view model.counter1)