Turbolinks 5で使えるオプション機能として、data-turbolinks-permanentというものがあります。
気になった動機
Rails+Turbolinks+Reactでシステムを組んでいて、Turbolinksでページごとのアセット読み込みは回避できるようになったのですが、Reactがページごとにマウント・アンマウントされるので、「同じものを再生成するコストが無駄」、また「Ajaxでロードするデータを何度も取ってくる必要がある」などの非効率な点があったので、そちらを改善したくなってきました。
そうしたところ、Turbolinksで対応できるとわかったので、取り入れてみた次第です。
data-turbolinks-permanentとは
Turbolinksで読み込むページ内に、<div id="some-id" data-turbolinks-permanent></div>のようにdata-turbolinks-permanent属性を指定したエレメントがあると、Turbolinksによるページ遷移の後も同じエレメントを再利用するようになります。なお、「idが同じ」ものだけ引き継がれますので、idの付与は必須となります。
JavaScriptの世界から見た挙動
もちろん、単なるHTMLを持ち越してもそこまで魅力があるわけではないので、主戦場はJavaScriptウィジェット、ということになります。ということで、イベント段階での挙動を見てみると、次のようになっていました。
-
turbolinks:before-render時点:永続する要素はまだdocument.bodyの中にあって、イベントで取ってこられるe.data.newBodyには上書きされる予定のdata-turbolinks-permanentつきエレメントが残っている -
turbolinks:load時点:永続する要素も新しいbody内部へ移動が完了して、それがdocument.bodyになっている
実際に何かしらのウィジェットを渡り歩かせるには、JavaScriptでイベントを拾って、以下のような流れで動かすことになると思います。
-
turbolinks:before-renderの段階で新規マウントしようとしたときには、すでに永続的なマウントが行われていればスルーする - すでに永続的にセットされたものについては、
-
turbolinks:before-renderでe.data.newBodyもチェックして、新しいHTMLに存在しなければアンマウントする - ウィジェットから
<body>を読み取ってなにか処理を行うような場合、turbolinks:renderで正しい<body>に入ったところで処理を行わせる