概要
タイムラインのナビメニューにある「item」タブ(楽天市場商品情報付き投稿の絞り込み)に、2つの不具合があった。
- 草グラフが連動しない: itemフィルタを有効にしても、貢献グラフの表示が「全カテゴリ」のまま変わらなかった
- フィルタリングが1件しか表示されない: itemフィルタを有効にすると、初回SSRで表示されている1件のみが残り、他の投稿が消えてしまっていた
原因
草グラフ連動しない問題
貢献グラフコンポーネント(ContributionGraph)は、カテゴリ別のカウントマップ(どの日に何件投稿があるか)をサーバー側で計算して渡す仕組みになっている。
graph:filter イベントが発火されると、コンポーネント側で categoryData[filterType] を参照してグラフを再描画する。しかし、categoryData の初期定義に item キーが含まれておらず、undefined として扱われ all(全件)にフォールバックしていた。
また、ContributionGraph コンポーネントに itemDates という Props が存在せず、楽天市場商品情報付き投稿の日付リストがコンポーネントに渡されていなかった。
フィルタリングが1件しか表示されない問題
タイムラインには初回表示(SSR)と無限スクロールによる追加読み込みの2つのルートがある。
- 初回SSRのHTML:
data-has-product="1"属性が付与されていた(正常) - 無限スクロールAPI(
webapp/src/pages/api/timeline_feed.astro):data-has-product属性が付与されていなかった(欠落)
その結果、無限スクロールで追加されたアイテムはすべて data-has-product が未定義(!== '1')と判定され、クライアント側フィルタで非表示にされていた。
修正内容
1. ContributionGraphコンポーネントへ itemDates Propsを追加
// 楽天市場商品情報付きつぶやきの日付リストを受け取るPropsを追加
itemDates?: string[];
受け取ったリストから日付別カウントマップを生成し、categoryData の item キーとして渡すようにした。
const itemCounts = buildCategoryCountMap(itemDates);
// ...
{
all: counts,
blog: blogCounts,
// ...
item: itemCounts // 追加
}
クライアント側の categoryData 初期値にも item: {} を追加した。
2. ページのContributionGraph呼び出しに itemDates を渡す
サーバー側で楽天市場商品情報付き投稿の日付リストがすでに productDatesForGraph として計算されていたが、コンポーネントへ渡されていなかった。これを itemDates={productDatesForGraph} として渡すよう修正した。
3. 無限スクロールAPIのアイテムに data-has-product 属性を追加
無限スクロール用APIのレスポンスHTMLにも、SSR側と同じ data-has-product 属性を付与するよう修正した。
data-has-product={(entry.entryType === 'note' && entry.product_info) ? '1' : undefined}
教訓
タイムラインフィルターは「SSR初回表示」「無限スクロールAPI」「草グラフ」の3層で構成されている。新しいフィルターを追加した際や修正する際は、3層すべてに対応が必要か確認すること。今回はSSR側のみ実装されていた属性が、無限スクロールAPI側に反映されていなかったことが原因だった。