先日、このようなアプリを作りました。
こちらです
スタート日時と、終了日時を設定するUI部分です。
書き始めてMsgが大量に必要になりそうだという事に気づきました。
日の設定にDownとUpの2つ、時の設定に4つ、分の設定に4つ。
それがスタートと終了の2つなので20個。
type Msg
= DownStartDays
| UpStartDays
| DownEndDays
| UpEndDays
-- ....
書き始めて嫌になりました。
最初はたとえば「時」だけ作り始め、Msg,update,viewのどれも長くなりそうでなんとかしなければと思いました。
メッセージに値を含める
まずは、DownStartHours
, DownStartHoursFive
などとせずにメッセージに値を含めることにしました。
type Msg
= DownStartHours Int
update msg model =
case msg of
DownStartHours step ->
( downHours step model.startEnd.start
|> setStartPoint model
, Cmd.none
)
DownEndHours step ->
( downHours step model.startEnd.end
|> setStartPoint model
, Cmd.none
)
view model =
div []
[ button [ onClick (DownStartHours 1) ] [ text "⬇" ]
, button [ onClick (DownStartHours 5) ] [ text "5⬇" ]
]
こんな感じです。
すぐに止め、StartかEndかも値で渡すようにしました。
type Msg
= DownHours PointType Int
type PointType
= Start
| End
update msg model =
case msg of
DownHours ptype step ->
case ptype of
Start ->
( downHours step model.startEnd.start
|> setStartPoint model
, Cmd.none
)
End ->
( downHours step model.startEnd.end
|> setEndPoint model
, Cmd.none
)
view model =
div []
[ button [ onClick (DownHours Start 1) ] [ text "⬇" ]
, button [ onClick (DownHours Start 5) ] [ text "5⬇" ]
]
あまり変わっていない感じがしますが、view部分は短くなりました。
view model =
div []
[ viewHours Start model.startEnd.start.hour
, viewHours End model.startEnd.end.hour
]
viewHours : PointType -> Int -> Html Msg
このようにできるようになったので。
Down,UpからUpdateと抽象化してみた
最初からDown 5
やUp 5
とせずに、Update 5
やUpdate -5
とすればとは思っていました。
しかし、「時」のカウントアップでは23を超えたら0に、カウントダウンでは0を下回れば23にと愚直にしていたのが悩みどころでした。(これもなんとかしたい)
都合よく、ループする数字を作ってみました。
こちらです。
import Looper as Lp
updateHours : Int -> StartEnd.Point -> StartEnd.Point
updateHours amount point =
{ point | hour = Lp.new point.hour 0 23 |> Lp.add amount |> Lp.get }
update msg model =
UpdateHours amount ptype ->
case ptype of
Start ->
( updateHours amount model.startEnd.start
|> setStartPoint model
, Cmd.none
)
End ->
( updateHours amount model.startEnd.end
|> setEndPoint model
, Cmd.none
)
こんな感じになり、なかなか短くなったと思います。
modelを渡したい(けど)
update msg model =
UpdateHours amount ptype ->
case ptype of
Start ->
updateHours amount model.startEnd.start
End ->
updateHours amount model.startEnd.end
--
UpdateHours 1 Start
UpdateHours 1 End
このようにせず
update msg model =
UpdateHours amount date ->
updateHours amount date
--
UpdateHours 1 model.startEnd.start
UpdateHours 1 model.startEnd.end
このようにしてしまえば、と思いそうですが、これは危なそうです。
[Elm] Msg に更新後の値を含めるのは要注意
ところで
削除機能付きのTodoアプリみたいなものを作ったことがあるのですが、今思えばあれも少々危ういのかもしれません。
List.indexedMapをこんなふうに利用して削除機能を実現できるのか!、と思いましたが。
[0 1 2 3 4 5]
List.indexedMapを利用し3と4を削除する
---
> Del 3
> Del 4
update [0 1 2 3 4 5] =
Del 3
update [0 1 2 4 5] =
Del 4
=> [0 1 2 4]
---
[0 1 2 5]を望んていたはず。
---
> Del todos.id
これならよさそう
実際には高橋名人のような連打でもなんの問題もないのだろうと思います。