概要
package.elm-lang.orgを参考に、一度取得したデータを保持して再取得しない仕組みを試した。
もともとはマークダウンを取得して表示する処理。
一度取得したものは取得しない処理を追加。
ソースの変更点についてメモ
Session.elm
package.elm-lang.orgは author project versionをディレクトリのキーにしていたので、
こちらはマークダウンのファイル名とバージョンで一意にするようにする。
マークダウンはほぼ更新しない予定なのでバージョンはオマケ。
Session.elm
module Session exposing (Data, Version, addMarkdown, empty, fetchMarkdown, getMarkdown, markdownUrl, toMarkdownKey)
import Dict
import Http
import Json.Decode as Decode
import Url.Builder as Url
type alias Version =
Float
-- SESSION DATA
type alias Data =
{ markdowns : Dict.Dict String String
}
empty : Data
empty =
Data Dict.empty
-- Markdown
toMarkdownKey : String -> Version -> String
toMarkdownKey fileName version =
fileName ++ "@" ++ String.fromFloat version
getMarkdown : Data -> String -> Version -> Maybe String
getMarkdown data fileName version =
Dict.get (toMarkdownKey fileName version) data.markdowns
addMarkdown : String -> Version -> String -> Data -> Data
addMarkdown fileName version markdown data =
let
newMarkdowns =
Dict.insert (toMarkdownKey fileName version) markdown data.markdowns
in
{ data | markdowns = newMarkdowns }
fetchMarkdown : (Result Http.Error String -> msg) -> String -> Cmd msg
fetchMarkdown toMsg fileName =
Http.get
{ url = markdownUrl fileName
, expect = Http.expectString toMsg
}
markdownUrl : String -> String
markdownUrl fileName =
Url.absolute [ "assets", "markdown", fileName ] []
Page/Markdown.elm
Sessionとバージョンをモデルに追加している。
Page/Markdown.elm
import Markdown
+import Session
import Skeleton exposing (viewLink, viewMain)
Page/Markdown.elm
type alias Model =
- { fileName : String
+ { session : Session.Data
+ , fileName : String
+ , version : Session.Version
, state : State
, naviState : NaviState
}
initでセッションとバージョンを引数に追加。
また、セッションにデータがあるか問い合わせる処理を追加。
なければ変更前と同様にHttpから取得する。
Page/Markdown.elm
-init : String -> ( Model, Cmd Msg )
-init fileName =
- ( Model fileName Init Close
- , getMarkdown GotMarkdown fileName
- )
+init : Session.Data -> String -> Session.Version -> ( Model, Cmd Msg )
+init session fileName version =
+ case Session.getMarkdown session fileName version of
+ Just markdown ->
+ let
+ model =
+ Model session fileName version (Loaded markdown) Close
+ in
+ ( model
+ , Cmd.none
+ )
+ Nothing ->
+ -- ページの初期化
+ -- 最初のModelを作ると同時に、ページの表示に必要なデータをHttpで取得
+ ( Model session fileName version Init Close
+ , Session.fetchMarkdown GotMarkdown fileName
+ )
updateでは、取得したデータをセッションにいれる処理を追加。
Page/Markdown.elm
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
--- init での Http リクエストの結果が得られたら Model を変更する
case msg of
case msg of
GotMarkdown (Ok markdown) ->
- ( { model | state = Loaded markdown }, Cmd.none )
+ ( { model
+ | state = Loaded markdown
+ , session = Session.addMarkdown model.fileName model.version markdown model.session
+ }
+ , Cmd.none
+ )
GotMarkdown (Err err) ->
( { model | state = Error err }, Cmd.none )
Main.elm
Main.elm
import Route exposing (..)
+import Session
import Skeleton exposing (Details, view)
exitで、ページ遷移時にセッションを引き継ぐ処理を行っている。
ここでは暫定的に、マークダウンのページ間でのみセッションを引き継ぐ。
後に、package.elm-lang.orgのように、すべてのページのモデルにsessionをくみこむ予定。
Main.elm
+exit : Model -> Session.Data
+exit model =
+ case model.page of
+ MarkdownPage m ->
+ m.session
+
+ _ ->
+ Session.empty
goTo : Maybe Route -> Model -> ( Model, Cmd Msg )
goTo maybeRoute model =
+ let
+ session =
+ exit model
+ in
case maybeRoute of
Nothing ->
( { model | page = NotFound }
引数にセッションとバージョンを追加。
Main.elm
Just Route.PrivacyPolicy ->
let
( markdownModel, markdownCmd ) =
- Markdown.init "privacy-policy.md"
+ Markdown.init session "privacy-policy.md" 1.0
in
( { model | page = MarkdownPage markdownModel }
, Cmd.map MarkdownMsg markdownCmd
)
Just Route.About ->
let
( markdownModel, markdownCmd ) =
- Markdown.init "about.md"
+ Markdown.init session "about.md" 1.0
in
( { model | page = MarkdownPage markdownModel }
, Cmd.map MarkdownMsg markdownCmd
)
Just Route.Agreement ->
let
( markdownModel, markdownCmd ) =
- Markdown.init "agreement.md"
+ Markdown.init session "agreement.md" 1.0
in
( { model | page = MarkdownPage markdownModel }
, Cmd.map MarkdownMsg markdownCmd
)