2017-06-13 51 views
0

我最近開始使用Elm,並遇到更新函數的問題。我的目標是將我的大文件Main.elm分割成多個較小的文件,但爲此我首先嚐試將主要組件拆分成同一文件中的較小組件。爲此,我非常依賴this very informative guide在基本的Elm應用中重構更新功能

分割模型和init(我已經爲DiceRoller做過)是非常簡單的,對於View來說它是微不足道的。不幸的是,更新並不那麼重要。

目前,它看起來像這樣(在Main.elm文件的主分支)

type Msg = Change String 
    | Name String 
    | Password String 
    | PasswordAgain String 
    | Roll 
    | NewFace Int 
    | SearchImages 
    | NewSearchResult (Result Http.Error (List String)) 
    | ChangeTermInput String 

update : Msg -> Model -> (Model, Cmd Msg) 
update msg model = 
    case msg of 
     Change newContent -> 
      ({ model | content = newContent }, Cmd.none) 
     Name name -> 
      ({ model | name = name }, Cmd.none) 
     Password password -> 
      ({ model | password = password }, Cmd.none) 
     PasswordAgain password -> 
      ({ model | passwordAgain = password }, Cmd.none) 
     Roll -> 
      (model, Random.generate NewFace (Random.int 1 100)) 
     NewFace newFace -> 
      ({ model | diceRoller = { dieFace = newFace} }, Cmd.none) 
     SearchImages -> 
      (model, getSearchResult model.termInput) 
     NewSearchResult (Ok newResult) -> 
      ({ model | termResult = newResult }, Cmd.none) 
     NewSearchResult (Err _) -> 
      (model, Cmd.none) 
     ChangeTermInput term -> 
      ({ model | termInput = term}, Cmd.none) 

,我設法得到它多一點精緻,但是這並不編譯(見this Main.elm in the refactoring branch):

type DiceRollerMsg = Roll 
    | NewFace Int 

type Msg = Change String 
    | Name String 
    | Password String 
    | PasswordAgain String 
    | MsgForDiceRoller DiceRollerMsg 
    | SearchImages 
    | NewSearchResult (Result Http.Error (List String)) 
    | ChangeTermInput String 

updateDiceRoller : DiceRollerMsg -> DiceRoller -> DiceRoller 
updateDiceRoller msg model = 
    case msg of 
     Roll -> 
      model 
     NewFace newFace -> 
      { model | dieFace = newFace} 

updateDiceRollerCmd : Msg -> Cmd Msg 
updateDiceRollerCmd msg = 
    case msg of 
     Roll -> 
      Random.generate NewFace (Random.int 1 100) 
     NewFace newFace -> 
      Cmd.none 

updateCmd : Msg -> Model -> Cmd Msg 
updateCmd msg model = 
    Cmd.batch 
     [ updateDiceRollerCmd msg 
     , getSearchResult model.termInput 
     ] 

updateModel : Msg -> Model -> Model 
updateModel msg model = 
    case msg of 
     Change newContent -> 
      { model | content = newContent } 
     Name name -> 
      { model | name = name } 
     Password password -> 
      { model | password = password } 
     PasswordAgain password -> 
      { model | passwordAgain = password } 
     MsgForDiceRoller msg -> 
      { model | diceRoller = updateDiceRoller msg model.diceRoller} 
     SearchImages -> 
      model 
     NewSearchResult (Ok newResult) -> 
      { model | termResult = newResult } 
     NewSearchResult (Err _) -> 
      model 
     ChangeTermInput term -> 
      { model | termInput = term} 

update : Msg -> Model -> (Model, Cmd Msg) 
update msg model = 
    (updateModel msg model, updateCmd msg model) 

由於模式與DiceRollerMsg相匹配,但它試圖匹配消息,因此無法在updateDiceRoller中的Role中的類型不匹配的情況下進行編譯。如果我只是將輸入和返回類型更改爲DiceRollerMsg,我會得到:函數updateDiceRollerCmd期望的參數是:DiceRollerMsg但它是:消息

另外,我不認爲updateCmd中的Cmd.batch是最佳解決方案。

我很感謝任何關於製作更好的Elm應用程序的意見,也包括這些問題之外。

回答

0

編譯錯誤源於使用Msg作爲輸入,返回值爲updateDiceRollerCmd而case語句使用DiceRollerMsg。您可以通過從MsgForDiceRoller進行模式匹配來修復此功能。

updateDiceRollerCmd : Msg -> Cmd Msg 
updateDiceRollerCmd msg = 
    case msg of 
     MsgForDiceRoller Roll -> 
      Random.generate NewFace (Random.int 1 100) 
       |> Cmd.map MsgForDiceRoller 

     _ -> 
      Cmd.none 

。在你的觀點多了一個編譯錯誤,你將需要改變onClick RollonClick (MsgForDiceRoller Rool)

+1

哇,他們不是在開玩笑對榆樹社區的工作效率,非常感謝!我對這些映射器一無所知,並且絕對沒有想到可能需要在onclick中投射。 – mdworld