elmでNavigationを使ったルーティング

書いてみたら意外と面倒だったのでとりあえず楽そうな方法で済ませた。

Navigation.program

ルーティングが必要な時はHtml.programの代わりにNavigation.programを使う。

initやupdateなどを渡すのは同じだが、(Location -> msg)も引数に取るのが違う。

modelの初期データ

initにNavigation.Locationが渡ってくるようになるのでhashを現在のrouteとして格納する。

初期処理としては不十分だけど今回はviewの切り替えまでということで。

type alias Model =
    { route : String }

init : Navigation.Location -> ( Model, Cmd msg )
init location =
    ( Model location.hash, Cmd.none )

ルーティング用のupdate

ルーティングに変更があったらhashをモデルに格納する。ルーティングの変更自体は普通にhref=“#hoge"でOK。

type Msg
    = UrlChange Navigation.Location

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        UrlChange location ->
            ( { model | route = location.hash }, Cmd.none )

viewをmodel.routeで切り替え

pageという関数を用意してviewの切り替えをする。今回は手抜きして文字列の比較で済ませた。

page : Model -> Html msg
page model =
    case model.route of
        "#home" ->
            homeView model

        "#about" ->
            aboutView model

        _ ->
            homeView model

課題

まずはページの初期処理。たぶんちゃんとMsgを用意してそこで初期処理を行ってから、newUrlで遷移させる形になるはず。また、遷移したときだけじゃなくてinitでもurlを見てページの初期処理が必要になると思う。

あとはurlも文字列のパターンマッチじゃなくてparseしてtypeでのパターンマッチにするとか。

今回は手抜きしてるけどそこら辺も真面目にやったら結構面倒くさそう。

参考