The Elm Architecture(Elm 基本結構)說明

The Elm Architecture(TEA)實際上就是 Redux 或是 Vuex 不過是寫在 Elm 裡。實際上 Redux 跟 Vuex 都是基於 TEA 的想法而來的,所以 TEA 可以算是⋯⋯先鋒者吧?

在 Elm 中會很常用到 TEA 這種結構方式,實作方法比起在 JavaScript 上要來得簡單,且 TEA 有助於未來前端的擴展因為十分具有彈性。

基本樣貌

TEA 會將 Elm 清楚地切分成三個區塊:

  • Model(模型)-應用程式中的狀態集(State)。
  • Update(更新)-更新狀態集的函式集。
  • View(視圖)-顯示 HTML 的地方。

下面是個官方的計數器範例

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


main =  
  App.beginnerProgram { model = model, view = view, update = update }


-- MODEL

type alias Model = Int

model : Model  
model =  
  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 (toString model) ]
    , button [ onClick Increment ] [ text "+" ]
    ]

說明

在 Model 的部分你可以看到被定義成了 Int 型態,因為這只是個簡單的計數器範例,所以我們只將 Model 拿來存放計數。

type alias Model = Int  

然後 Update 的部分可以看到被定義了兩個動作,一個是 Increment(增加)、另一個是 Decrement 減少。

type Msg = Increment | Decrement  

當我們決定了 Update 有哪些動作之後,我們還要撰寫當我們接收到這些更新動作時該做出什麼樣的事情,而這部分還是屬於 Update。

稍微注意一下的是在 TEA 結構中,當你想要改變狀態(State)的時候,你必須呼叫 Update,而不是直接更改狀態,這也能夠集中你所有會更改狀態的函式,不會分散至個角落。

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

    Decrement ->
      model - 1

所以當你接收到了 Increment 的指示(Msg),你將 Model + 1,就這麼簡單。

在 View 的部分你並沒有辦法直接在 Elm 中撰寫 HTML 或是 Pug(Jade),你必須透過 elm-lang/html 套件來撰寫 HTML5,長相有點像是一堆的陣列或是物件。

view : Model -> Html Msg  
view model =  
  div []
    [ button [ onClick Decrement ] [ text "-" ]
    , div [] [ text (toString model) ]
    , button [ onClick Increment ] [ text "+" ]
    ]

這裡看到更多的相關範例。

你可以發現其中有些按鈕具備 onClick 功能,跟在後面的是 DecrementIncrement,當按鈕按下時會傳遞後面的指示(Msg)給 Update,然後 Update 接收到指示後即會更變狀態(State)。

這也是為什麼 view 被定義成 Html Msg,因為我們的 HTML 會產生 Msg 指示。

順帶一提,要注意的是 buttondiv 都是 Elm 中的函式而不是 HTML 標籤,所以當你要使用更多其他元素的時候,請記得在上方匯入相關的「函式」(如 spana 等)。

為什麼是這種 View?

如果你是 Elm 的初學者,你可能會好奇為什麼不直接讓使用者撰寫 HTML 或是 Pug(Jade),在這裡我就直接原文照翻了,看起來是為了統一大家的做法還有保有 Elm 自己的控制空間。

自從我們使用的是一般的 Elm 函式,我們有完全的能力可以透過 Elm 程式語言來協助建造我們的視圖!我們可以將重複的部分寫成函式。還能夠將輔助區段寫成模塊然後在其他地方直接引用。也可以用同樣的測試框架、函式庫測試其他的 Elm 程式碼。任何東西在 Elm 中都是 100% 可以共用。而且不需要和模板語言搭配再一起!

在這其實還有一個更深層的故事。View 的程式結構能令人一目瞭然。我們帶入一個 Model 然後產生了一些 Html。就這樣。沒有必要直接手動更變 Dom,Elm 在背後都有注意到這些細節。這給予了 Elm 更多的空間來管理優化層面且最終的渲染也夭壽快。簡單說就是寫更少的程式碼但是跑得更快!


圖示來源:3-point diagram by ROZMOWA from the Noun Project