Elmのお勉強3: webアプリの作成 前編

Elm

Elmアーキテクチャについて

Elm アーキテクチャでは、3 つの項目によって成り立っている。

  • Model … ステート
  • Update … ステートの更新。メッセージ(Msg)を受け取って Model を更新。
  • View … html への描画。

これらの頭文字をとって、MVU(Model-View-Update)アーキテクチャとも呼ばれるらしい。

単純なhtmlの作成

h1p を置いただけの html を表示させてみる。

module Main exposing (main)

import Html exposing (..)
import Html.Attributes exposing (..)


main =
    main_ [ class "main" ]
        [ h1 [ class "title" ] [ text "Hello World" ]
        , p [ class "text" ] [ text "Hello Elm" ]
        ]

はじめに、div, h1, p などの要素を取得するために Html モジュールを丸ごとインポート。
次に、Attribute(属性値)も設定するため、Html.Attributes もインポートしている。

main 関数の中で、描写する html 部分を記述している。
div [] [ text "Foo" ] のように書いていく。
今回は Html.Attributes をインポートしているので、1 つ目の引数[]に class 関数を入れて、class を指定できている。
また、上コードのように、第 2 引数の[]に要素を書けば入れ子にできる。

保存したら elm reactor でローカルホストを立ち上げ、elm ファイルにアクセスする。

elm reactor

表示される。

ElmのページでHello Worldが表示された

Modelの作成

さっきのコードは、main 内で Html モジュールを用いて静的なページを作成しただけ。
次は Elm アーキテクチャに結びつける。

「朝」「昼」「夜」の 3 ボタンがあって、押すとタイトルと文字色が変わるだけのものを作ってみる。

最初の行に import Browser を追加。
Browser は、プログラムの作成に特化したモジュール。

main 関数に、 Browser.sandbox を定義する。

main =
    Browser.sandbox { init = init, update = update, view = view }

Browser.sandbox は、HTTP 通信や JavaScript との連携ができない初心者向けのもの。
これが Browser.element -> Browser.document -> Browser.application…となることでやれることが多くなる。

レコードの中には、init(初期化されたステート)、update(更新用)、view(描写部分)が入る。

Modelの作成

まず、Model 部分を記述していく。

-- Model


-- time, colorという情報がStringで入る
type alias Model =
    { time : String
    , color : String
    }


-- 初期状態
init : Model
init =
    { time = "昼"
    , color = "green"
    }

Updateの作成

update 部分には、まず Msg というユニオン型を用意して、
そこに中身を入れていく。

-- Update


type Msg
    = Morning
    | Noon
    | Night

次に、update 関数を置き、
case 文で、ユニオン型を使って分岐させる。

update msg model =
    case msg of
        Morning ->
            { model | time = "朝", color = "red" }

        Noon ->
            { model | time = init.time, color = init.color }

        Night ->
            { model | time = "夜", color = "blue" }

ユニオン型の中身と case 文の中身が一致しない、足りない場合はエラーが出る。

Viewの作成

View 部分では button を置き、第二引数に [ onClick Msg内の値 ] を指定する。

-- View


view model =
    main_ [ class "main" ]
        [ h2 [ style "color" model.color ] [ text model.time ]
        , button [ onClick Morning ] [ text "朝" ]
        , button [ onClick Noon ] [ text "昼" ]
        , button [ onClick Night ] [ text "夜" ]
        ]

最終的なコード

import Browser
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (..)


main =
    Browser.sandbox { init = init, update = update, view = view }



-- Model


type alias Model =
    { time : String
    , color : String
    }


init : Model
init =
    { time = "昼"
    , color = "green"
    }



-- Update


type Msg
    = Morning
    | Noon
    | Night


update msg model =
    case msg of
        Morning ->
            { model | time = "朝", color = "red" }

        Noon ->
            { model | time = init.time, color = init.color }

        Night ->
            { model | time = "夜", color = "blue" }



-- View


view model =
    main_ [ class "main" ]
        [ h2 [ style "color" model.color ] [ text model.time ]
        , button [ onClick Morning ] [ text "朝" ]
        , button [ onClick Noon ] [ text "昼" ]
        , button [ onClick Night ] [ text "夜" ]
        ]

流れ

Model

{ time: String }Model 型が定義される。
init で、model の初期値を time: "昼" にする。

View

button [ onClick Night ] でボタンを描画し、それを押すと、 Html.Event によってイベントが渡される。
その際 Msg に、Night が渡される。

Update

Msg が受け取った Night を、update 関数の case 文を参照して処理を決める。
case 文では、全てのパターンが存在することをコンパイル前の段階で保証するので、Night がなかった時は考えない。
Night での処理によって、 model.time の値が「夜」model.color の値が "blue" に更新される。

MVUによって、「朝」という文字列から「夜」に更新された画像