読者です 読者をやめる 読者になる 読者になる

Elm --- Model、View、Update

Elm

Elmの基本構造を、Elmのサンプルにあるカウンタを用いて紹介します。

作成するアプリケーション

ボタンを押すと数値が+1もしくは-1される簡単なものです。
f:id:any-programming:20170122164525p:plain

Elmの基本構造

Model アプリケーションの状態を保持
Update 送られてくるメッセージに従ってModelを更新
View ModelからHtmlオブジェクトを作成

f:id:any-programming:20170122175848p:plain

Modelの作成

カウンタの値を保持するcountを持ったレコードを作成します。

type alias Model = { count : Int }


メッセージの作成

Update関数に送るメッセージのユニオンタイプを定義します。

type Msg 
    = Increment 
    | Decrement


Updateの作成

Incrementを受け取ったらcountを+1、Decrementを受け取ったらcountを-1するよう実装します。
{ model | count = ... }はcountの値を変更したmodelのコピーを作成します。
今回はcountしかないので{ count = ... }と同じです。

update msg model =
  case msg of
    Increment ->
      { model | count = model.count + 1 }

    Decrement ->
      { model | count = model.count - 1 }


Viewの作成

Decrementを送信するボタン、Incrementを送信するボタン、countを表示するテキストからなるHtmlオブジェクトを作成します。
基本的に
要素 [属性] [子要素]
の書式になっています。

view model =
  div []
    [ button [ onClick Decrement ] [ text "-" ]
    , div [] [ text (toString model.count) ]
    , button [ onClick Increment ] [ text "+" ]
    ]


mainの作成

Modelの初期値、View、Updateを組み合わせてアプリケーションを作成します。

main =
  beginnerProgram 
  { model = { count = 0 }
  , view = view
  , update = update 
  }


コード全体

import Html exposing (beginnerProgram, div, button, text)
import Html.Events exposing (onClick)

type alias Model = { count : Int }

type Msg 
    = Increment 
    | Decrement

update msg model =
  case msg of
    Increment ->
      { model | count = model.count + 1 }

    Decrement ->
      { model | count = model.count - 1 }

view model =
  div []
    [ button [ onClick Decrement ] [ text "-" ]
    , div [] [ text (toString model.count) ]
    , button [ onClick Increment ] [ text "+" ]
    ]

main =
  beginnerProgram 
  { model = { count = 0 }
  , view = view
  , update = update 
  }


基本構造再確認

Incrementのメッセージが送られた時の流れを下図に示します。
f:id:any-programming:20170122201908p:plain

Htmlの差分更新

ElmではHtmlオブジェクトを毎回Html化せずに、前回のHtmlオブジェクトと比べて変更した部分のみHtmlの変更を行うようになっています。そのためパフォーマンスを出すことが可能となっています。
f:id:any-programming:20170122203519p:plain