StimulusとlocalStorageで最近閲覧したページリストを保存する方法

「最近閲覧したページ」リストを作成することで、簡単なナビゲーションと最近アクセスしたコンテンツの履歴を提供し、ユーザー体験を大幅に向上させることができます。すでにRailsを使用しているので、Stimulusを活用します。また、情報をサーバーに保存する代わりに、localStorageを使用してセッション間で閲覧したページのデータを永続化します。

なぜStimulusとlocalStorageを使うのか?

通常、UI操作については、できるだけ軽量に保つことを好みます。だからStimulusよりAlpineJSを好みます。

しかし、この場合、JavaScriptにもう少しロジックがあるため、Stimulusは良い選択です。

また、クライアントサイドのストレージメカニズムとしてlocalStorageを使用します。ページ履歴のような機密性のない情報を保存するのに理想的です。なぜなら、ユーザーがブラウザを更新したり閉じたりした後もデータが保存されるからです。

localStorageを使用する欠点は、ユーザーが別のコンピュータからログインした場合、これが同期されないことです。Stimulusコントローラに追加のロジックを加えてこの情報を同期することは可能ですが、私のようなユースケースであれば、おそらく必要ありません。

目標

私たちの目標は、以下を行う最近閲覧したページリストを構築することです:

  • ユーザーが訪問したページを追跡する。
  • ページ名と短い説明などのメタデータを保存する。
  • 最新の20ページまでの最近訪問したページを表示する。
  • localStorageを使用してセッション間でこのデータを永続化する。

Stimulusコントローラ

以下は、ユーザーが訪問したページの追跡と保存を処理するStimulusコントローラです:

// app/javascript/controllers/recently_viewed_controller.js
import { Controller } from "@hotwired/stimulus";

export default class extends Controller {
  static targets = ["currentPath"];

  connect() {
    if (this.currentPathTargets.length !== 0) {
      let name = this.currentPathTarget.dataset.name;
      this.saveCurrentPath(name);
    }
  }

  saveCurrentPath(name) {
    let path = window.location.pathname;

    // path、name、descriptionを含むオブジェクトを作成
    let pathObject = { path: path, name: name };

    // 同じpathを持つ既存のオブジェクトを削除
    let visitedPaths = this.removePathsContaining(path);

    // 新しいオブジェクトを配列の先頭に追加
    visitedPaths.unshift(pathObject);

    // 最新の20エントリのみを保持
    if (visitedPaths.length > 20) {
      visitedPaths = visitedPaths.slice(0, 20);
    }

    // 更新された配列をlocalStorageに保存
    localStorage.setItem("visitedPath", JSON.stringify(visitedPaths));
  }

  removePathsContaining(substring) {
    // localStorageから既存の配列を取得
    let visitedPaths = JSON.parse(localStorage.getItem("visitedPath")) || [];

    // pathにsubstringを含むオブジェクトをフィルタリング
    visitedPaths = visitedPaths.filter(
      (item) => !item.path.includes(substring)
    );

    return visitedPaths;
  }

  resetPaths() {
    // localStorageからvisitedPathアイテムをクリア
    localStorage.removeItem("visitedPath");
  }
}

このコントローラをアクティブにし、特定のページを追跡するには、bodyタグにこれを追加する必要があります:

<body data-controller="smooth-scroll recently-viewed">
  <div data-recently-viewed-target="currentPath" data-page-name="<%= @page_name %>">
  </div>
  /* あなたのコード */
</body>

上記のコードをリファクタリングしたり、組み合わせたりするオプションがあります。私のユースケースでは、コントローラをbodyタグに追加してアクティブ化し、内部のdivタグを追加した場合にオプションでページを保存したかったです。

localStorageからリストを使用する

リストができたので、次のようにアクセスできます:

window.recentlyVisitedPaths = JSON.parse(localStorage.getItem("visitedPath")) || [];

値はJSONとして返され、Stimulusや同様のものを使用してレンダリングできます。

最終更新日 2024年8月31日