見出し画像

Hotwireことはじめ 〜詳解② Turbo Framesで画面の部分的な書き換えを行う〜

はじめに

こんにちは、万葉でバックエンドエンジニアをしている吉原です。

この記事は、2022年12月13日に開催されたRubyセミナーOnlineでの「Hotwireことはじめ」セッションを解説する記事シリーズの第3回目です。

前回の記事はHotwireことはじめ〜詳解① Turbo Driveの有効化で画面変化をなめらかにする〜です。こちらでは Turbo Drive の設定とその効果について解説していますので、まだご覧になっていなければ是非こちらも併せてお読みください。

今回はサンプルアプリの改善を題材に、Turbo Frames の具体的な使いこなしを解説していきたいと思います。

つぶやきの一覧部分だけを書き換える

アプリの現状

まずは、Turbo Frames を使用する前のサンプルアプリの状態を確認しておきましょう。1-use-drive ブランチにチェックアウトしてアプリを起動してください。

参考までに、前回記事の状態から操作する場合は次のようなコマンドでできます。また、環境構築がまだの方はリポジトリのREADMEに記載されている起動手順に従って環境構築を行なってください。

$ git checkout 1-use-drive
$ cd hotwire-tw-demo
$ bin/dev

http://localhost:3000 にアクセスして、つぶやきの一覧画面を表示しましょう。この画面ではサイドバーの顔のアイコンをクリックすることで「きもち」によるつぶやきの絞り込みができるようになっています。

画面書き換え時に入力内容が消えてしまう様子

「なまえ」のフォームに注目してください。サイドバーで顔のアイコンをクリックすると、画面遷移が発生し、リロードが行われます(Turbo Driveによって画面が描画されます)。その結果、右側の入力欄エリアに入力した「吉原」という内容が消えてしまうことがわかります。

フォーム自体は顔アイコンのクリック前も後も変わらず画面に表示されているのに、入力した内容が失われてしまうというのは、ユーザーにとって良い体験ではありません。

では、どうすれば良いのでしょうか?

画面遷移時に書き換えを行いたい箇所

画面遷移の際に、表示内容の書き換えを行いたい箇所(上の画像の赤枠部分)のみがリロードされるようにすることができれば、入力内容が消えてしまう課題を解決することができそうです。

そこで、Turbo Framesの出番です!

Turbo Framesを使って解決する

Turbo Frames はページ遷移やフォーム送信時にページの特定の部分のみを置き換えられるようにするための仕組みです。前回の記事でご紹介した Turbo Drive はページの body 要素の全て(画面に表示される内容の全て)の置き換えを行っていたのに対して、Turbo Frames では更に狭い範囲を指定して置き換えることを可能にしてくれます。これによって、アプリ内で画面が変わる動きを高速化することができます。また、ユーザーによる入力済みのフォームなど、書き換えられて欲しくない部分の書き換えを防ぐことができます。

そこで、今回のアプリについて、先程の赤枠の部分だけをTurbo Framesで書き換えるようにしていきましょう。

まず、赤枠の部分に対応するビューのコードがどこなのかを確認しましょう。hotwire-tw-demo/app/views/emotions/index.html.erb 内の下記の部分のうち、<%= render partial: "emotion", collection: @emotions %> のところが赤枠部分に当たります。

<ol class="emotion-list w-100">
  <%= render partial: "emotion", collection: @emotions %>
</ol>

では、この <%= render … %> の部分を書き換えたいのだということを Turbo Frames 伝えましょう。そのためには、書き換えを行いたい部分を次のようにturbo_frame_tagで囲みます。

<ol class="emotion-list w-100">
  <%= turbo_frame_tag "emotions" do %>
    <%= render partial: "emotion", collection: @emotions %>
  <% end %>
</ol>

turbo_frame_tagで囲んだことによって出力される HTML がどう変わるかを確認しましょう。以下はturbo_frame_tag追加前のHTMLです。

turbo_frame_tag追加前

turbo_frame_tag追加後、出力されるHTMLは以下のように変わりました。turbo-frameタグの要素が追加されていることがわかります。

turbo_frame_tag追加後

turbo-frameタグで囲まれた領域(trubo-frameタグのid要素を"emotions"としているので、以後、"emotions" 領域と呼びます)ができ、リンクのクリックやボタンを押すなどの特定の操作をしたときにこの領域だけを書き換えることが可能になります。

次にどんな操作をしたときに "emotions" 領域を書き換えたいのかを指定します。

画面書き換え時に入力内容が消えてしまう様子(再掲)

サイドバーでの一覧の絞り込み時に画面全体がリロードされてしまう問題を解決したいので、サイドバーで顔アイコンをクリックしたときに "emotions" 領域だけが書き換わるようにしていきます。

まず、現在のサイドバーのリンク部分のコードを確認しましょう。以下のようになっています。

<%= link_to root_path(icon: Emotion.icons[:love]), class: "nav-link #{active_css_class(root_path + "?icon=0")}" do %>
  <%== show_icon(Emotion.icons[:love], width: 30, height: 30) %>
<% end %>

上記のリンクがクリックされた際に "emotions" 領域のみを書き換えるように修正します。

それには、リンクの要素(<a>タグ)に data-turbo-frame 属性で領域のID(この場合は"emotions")を指定します(※)。Railsのビューのコードとしては、下記のように、link_to メソッドを使って<a> タグを出力しますが、その際に属性として data: { turbo_frame: "emotions" } を指定します。

<%= link_to root_path(icon: Emotion.icons[:love]), class: "nav-link #{active_css_class(root_path + "?icon=0")}",
  data: { turbo_frame: "emotions" } do %>
  <%== show_icon(Emotion.icons[:love], width: 30, height: 30) %>
<% end %>

これにより生成されるHTMLは以下のようになります。

data-turbo-frame追加後

※今回のサイドバーのようにに目的のturbo-frame領域の外側にある<a>タグからTurbo Framesで遷移させるにはdata-turbo-frameをつける必要がありますが、領域の内側にある<a>タグの場合は、デフォルトで自分を囲んでいるturbo-frame領域に向かって Turbo Frames で遷移します。

完成形を確認する

これでリンクをクリックした際に、つぶやきの一覧部分である "emotions"領域だけが書き換えられるようになりました。実際に動作を確認してみましょう。

画面書き換え時に入力内容が消えなくなっている様子

顔アイコンリンクをクリックして絞り込み内容を変えても、入力内容が消えずに残っていることがわかります。リンククリック時に、ページ全体のリロードを行わず、一覧部分のみを書き換えるようになったからです。

おわりに

これで「詳解② Turbo Framesで画面の部分的な書き換えを行う」は終了です。Turbo Framesを有効化して、画面の部分的な書き換えができるようになったことを確認できました。

次回はTurbo Streamsを見ていきます。Turbo Streamsはこれまでに見てきたTurbo DriveやTurbo Framesよりも更に柔軟にDOM操作を行うための技術です。是非ご期待ください!


株式会社万葉ではエンジニアの採用を行っています!
https://everyleaf.com/we-are-hiring