ボタン
最初の例はインクリメントやデクリメントを行うカウンタの作成です。
以下にプログラムの全文を掲載しました。青い"Edit"ボタンをクリックして、オンラインエディタでいじってみましょう。ボタンの文字を書き換えてみてください。今すぐ青いボタンをクリック!
import Browser
import Html exposing (Html, button, div, text)
import Html.Events exposing (onClick)
-- MAIN
main =
Browser.sandbox { init = init, update = update, view = view }
-- MODEL
type alias Model = Int
init : Model
init =
0
-- UPDATE
type Msg = Increment | Decrement
update : Msg -> Model -> Model
update msg model =
case msg of
Increment ->
model + 1
Decrement ->
model - 1
-- VIEW
view : Model -> Html Msg
view model =
div []
[ button [ onClick Decrement ] [ text "-" ]
, div [] [ text (String.fromInt model) ]
, button [ onClick Increment ] [ text "+" ]
]
コードを少しいじってみたことで、疑問を持ったかもしれませんね。このmain
という値は何をしているのだろうか?どのようにして異なるパーツを組み合わせているのだろうか?と。コードを見ながら説明していきましょう。
Note: ここのコードは型注釈と 型エイリアス、カスタム型を使用しています。この節のポイントはThe Elm Architectureの雰囲気をつかむことなので、これらはもう少し後で取り上げます。もしこういった面で行き詰まっているならば上記の節を覗いてみることをおすすめします!
Main
main
はElmでは特別な値で、画面に何を表示するかを記述します。この例では、アプリケーションをinit
で初期化して、view
関数ですべてを画面に表示し、ユーザーからの入力をupdate
関数に渡します。これがプログラムの大まかな概要だと考えてください。
モデル
Elmでは、アプリケーションの状態をプログラムが扱える形にするモデル化が非常に重要です。モデルのポイントは、アプリケーションに関する情報を全てくまなくデータとして表現できるようにすることです。
カウンターを作るためには、増えたり減ったりする数を把握しておく必要がありますね。このケースでは、モデルが本当に小さなものになります。
type alias Model = Int
現在のカウントを把握しておくためにはInt
型の値だけが必要です。これは初期値で確認できます。
init : Model
init =
0
初期値はゼロで、各ボタンを押すと増えたり減ったりします。
View
これでモデルが用意できましたが、モデルの内容を画面に表示するにはどうすればいいでしょうか?それはview
関数の役割です。
view : Model -> Html Msg
view model =
div []
[ button [ onClick Decrement ] [ text "-" ]
, div [] [ text (String.fromInt model) ]
, button [ onClick Increment ] [ text "+" ]
]
このviewという関数はModel
を引数として受け取り、HTMLを出力します。ここでは、マイナスボタン、現在のカウント、プラスボタンを表示させることになります。
各ボタンにonClick
ハンドラーがあることに注目してください。クリックするとメッセージを生成するということです。つまりこのプラスボタンはIncrement
メッセージを生成しています。メッセージを生成するとはどういうことでしょうか、そして生成されたメッセージはどこに行くのでしょうか?update
関数に行きます!
Update
update
関数は、各種イベントで生成されたメッセージをきっかけとして、Model
が各場面でどのように変化するかを記述するものです。
たとえば今回の例では、update関数は以下のように定義されている2つのメッセージを受け取る可能性があります。
type Msg = Increment | Decrement
それでは、メッセージを受信したとき何をすべきかを update
関数にそのまま記述しましょう。
update : Msg -> Model -> Model
update msg model =
case msg of
Increment ->
model + 1
Decrement ->
model - 1
Increment
メッセージを受け取ったらモデルをインクリメントし、Decrement
メッセージを受け取ったらデクリメントします。
つまり何かメッセージを受け取るたびにupdate
に渡して実行して新しいモデルを取得します。次にview
を呼び出して新しいモデルを画面にどう表示するか計算します。これがその後も繰り返されていきます!つまり、view によって表示された画面でユーザーが何か操作を行うとまたメッセージが生成され、それをupdate関数が受け取ってモデルを更新(update)し、viewがそのモデルを元にまた画面を表示(view)します。
全体像
これでElmのプログラムのすべてのパーツを見たわけですが、先ほど見た図のどこにどれが対応するかを整理してみると、もう少しわかりやすいかもしれません。
Elmは初期値を画面に描画することから始まります。そこから以下のループに入ります。
- ユーザーからの入力を待ちます
update
にメッセージを送ります- 新しい
Model
を生成します view
関数を呼び出して新しいHTMLを取得します- 画面上に新しいHTMLを表示します
- 繰り返します!
これがThe Elm Architectureの本質です。これから見るすべての例は、この基本的なパターンにわずかなバリエーションを加えたものになります。
演習: カウンターをゼロにリセットするボタンを追加してみましょう
Reset
バリアントをMsg
型に追加しますupdate
関数にReset
の分岐を追加しますview
関数にボタンを追加しますこのサンプルはこちらのオンラインエディタで編集できます。
これがうまくいったら、10ずつ増えるボタンを追加してみてください。