FLINTERS Engineer's Blog

FLINTERSのエンジニアによる技術ブログ

The Elm Architectureの構成とデータフロー

こんにちは、丸山です。

前回フロントエンドの状態管理を考える一つの方法としてFluxを見てみました。 今回はThe Elm Architectureについて見ていきたいと思います。

The Elm Architectureとは

公式ガイドによればThe Elm Architectureは関数型プログラミング言語であるElmでアプリケーションを構築する際に使われるパターンで、 モジュール性やコードの再利用性、テストのしやすさなどに優れているということです。 Fluxの時と同じように、まずThe Elm Architectureの要素を見ていきます。

Model

アプリケーションの状態

Update

状態を更新する方法

View

HTMLとして状態を閲覧する方法

The Elm Architectureは以上の3つの要素から構成されます。
次に実際にコードを見て、これらがどう使われているのかを見ていきます。

The Elm Architectureのデータフロー

こちらはElmで書いたカウンターアプリのコードです(公式ガイドにあるサンプルコードを少し書き換えました)。

import Browser
import Html exposing (Html, text, p, div, button, form, input)
import Html.Events exposing (onClick, onInput)
import Html.Attributes exposing (value)

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

-- MODEL

type alias Model = Int

init : Model
init = 0

-- UPDATE

type Msg = Increment Int | Decrement Int

update : Msg -> Model -> Model
update msg model =
  case msg of
    Increment n ->
     model + n

    Decrement n ->
      model - n

-- VIEW
view : Model -> Html Msg
view model =
  div []
    [ div [] [ text (String.fromInt model) ]
    , button [ onClick (Increment 1) ] [ text "+1" ]
    , button [ onClick (Increment 10) ] [ text "+10" ]
    , button [ onClick (Decrement 1) ] [ text "-1" ]
    , button [ onClick (Decrement 10) ] [ text "-10" ]
    ]

ボタンを押すことで、そのラベルに書かれた計算が行われ結果が表示されます。

f:id:to_maruyama:20190405234319g:plain

データフローを追う前にまずは各要素を見ていきます。 Elmの仕様の詳細については省略しますが、できるだけ何をやっているのかわかるように説明したいと思います。

Model
type alias Model = Int

この部分がこのアプリケーションの状態になります。 Modelという型を定義しています(Int型にModelという別名を付けただけのものです)。
カウンターアプリにおける状態なので、計算された結果が格納されます。

Update

Updateには状態を更新する方法の定義とその内容が書いてあります。

type Msg = Increment Int | Decrement Int

ここでは状態を更新する方法の種類と更新に使われる値の定義をしています。 Int型の値を使ってIncrementを行う、またはInt型の値を使ってDecrementを行うといった意味になります。 FluxでいうところのActionのようなものです。

続く、

update : Msg -> Model -> Model
update msg model = ...

の部分で、実際にどうやって状態を更新するのかを書いています。

  case msg of
    Increment n ->
     model + n

    Decrement n ->
      model - n

この部分でメッセージがIncrementならModelに値(先ほどMsgのところでIntで定義した部分です)を足し、Decrementなら引くといったことをやっています。

View

Viewの部分ではModelを受け取り、HTMLを通して表示をしています。

div [] [ text (String.fromInt model) ]

またボタンをクリックすることでメッセージを発行するという定義もされています。

button [ onClick (Increment 1) ] [ text "+1" ]

この部分では、"+1"ボタンをクリックすることで Increment 1というメッセージが発行されるという動作を表しています。

最後にデータの流れを見ていきます。

例:"+1"ボタンがクリックされた場合

ViewからメッセージIncrement 1が発行される f:id:to_maruyama:20190406001637p:plain:h150:w500

Updateでメッセージを受け取り、その内容を見て状態の更新(Modelに対して+1)を行う f:id:to_maruyama:20190406003819p:plain:h200:w500

更新された状態がViewに渡され、計算された結果が表示される f:id:to_maruyama:20190406004313p:plain:h200:w500

終わりに

前回のFlux、今回のThe Elm Architectureと見てきましたが、Fluxでは状態と更新処理の管理はstoreで、The Elm ArchitectureではそれぞれをModelとUpdateが担っていましたが、どちらも決まった場所に置かれれていることは同じでした。
またFlux、The Elm Architecture共に流れは単一方向となっていたことがわかりました。
両者に共通する部分をまとめると、

  • データの流れがシンプル(単一方向)
    • データの取得・更新の流れの見通しがよくなる
  • 状態の管理と更新処理が特定の箇所にまとまっている
    • 管理や再利用がしやすくなる

が挙げられます。
この辺りが、状態管理における一つのパターンになるのではないかと思います。