こんにちは。野崎です。
先日、開催しました「microCMS Online Meetup」の際にイベントバナーが管理画面上部に表示されたのにお気づきでしたでしょうか?
実はこれもmicroCMSを使用してイベント情報を管理しています。
この記事では、microCMSのようなSPAアプリケーションでイベントバナーを表示させる方法を紹介します。
実装するもの
以下のような画面上部のバナーを表示・管理する仕組みを実装します。
管理画面(サービス内)に表示させるものなので以下のような仕様となっています。
- 何個も表示すると操作の邪魔になるので、一個のみの表示とする
- イベント情報が必要ないユーザーもいるので「閉じる」ボタンでバナーを消せるようにする
- Cookieを用いて、実装コストを下げる。
- イベント情報を表示するたびにCookieを保存するとパフォーマンスにも影響するので、イベント更新のたびにCookieを削除する
実装方法
microCMSで行っている実装方法を紹介します。
使用技術
microCMSではフロントエンドの開発にReactを使用しているので、その前提での解説になります。
microCMSのデータ取得にはReact Queryを使用しています。
取得するmicroCMSのAPIスキーマは以下のようなシンプルなものとなっています。
前章でも述べたとおり、イベントバナーの表示ロジックにはCookieを用いてイベントバナーの出しわけを行っています。
管理するためのReact Hooksを作成する
React Hooksを用いてイベントバナーの表示ロジックを実装します。
コンポーネント側に実装するのではなく、Hooks内に処理を実装することで、コンポーネント側ではmicroCMSの値を意識せずに実装をすることができます。
Hooksの全容を載せます(一部表示をサンプル用に省略・変更しています)。
import { useCallback, useState, useEffect } from 'react';
import { useQuery } from 'react-query';
import { useCookies } from 'react-cookie';
import { client } from "../lib/microcmsClinet"
import dayjs from 'dayjs';
export const useInfo = () => {
const getInfoQuery = useQuery(
['microcmsInfo'],
async () => {
return await client.get({
endpoint: 'info',
queries: { fields: 'id,title,link,publishedAt' },
});
},
{ staleTime: Infinity }
);
const { data: info, isLoading: isInfoLoading } = getInfoQuery;
const [cookies, setCookie, removeCookie] = useCookies([
`sample#cookie`,
]);
const [isInfoOpen, setInfoOpen] = useState<boolean>(
!cookies[`sample#cookie`]
);
const latestContentPublishedAt = info?.contents?.[0]?.publishedAt;
useEffect(() => {
if (latestContentPublishedAt > cookies[`sample#cookie`]) {
removeCookie(`sample#cookie`, {
path: '/',
});
setInfoOpen(true);
}
}, [cookies, latestContentPublishedAt, removeCookie]);
const closeInfo = useCallback(
(e) => {
setCookie(`sample#cookie`, new Date().toISOString(), {
path: '/',
expires: dayjs().add(20, 'year').toDate(),
});
setInfoOpen(false);
e.preventDefault();
},
[setCookie]
);
return {
// 最新の一件のみを返す
info: info?.contents?.[0],
isInfoOpen,
closeInfo,
isInfoLoading,
};
};
処理の詳細を解説します。
まずはReact QueryでmicroCMSのAPIを叩いてイベントバナーの情報を取得します。
ポイントはReact QueryのオプションstaleTime: Infinity
を設定していることです。
キャッシュを保持することにより余計な再取得を防ぐことができます。
またmicroCMSのクエリで fields
を指定してクエリを絞り込むことで、使用するデータのみ取得することができます。。
const getInfoQuery = useQuery(
['microcmsInfo'],
async () => {
return await client.get({
endpoint: 'info',
queries: { fields: 'id,title,link,publishedAt' },
});
},
{ staleTime: Infinity }
);
const { data: info, isLoading: isInfoLoading } = getInfoQuery;
次にイベントバーの「×」ボタンを押したときにイベントバナーを閉じる実装です。
閉じるボタンを押したときにCookieを保存して、一度閉じたバナーは表示されない仕組みを実装します。
Cookieを扱うのに、react-cookieを使用しています。
https://www.npmjs.com/package/react-cookie
const [cookies, setCookie, removeCookie] = useCookies([
`sample#cookie`,
]);
// Cookieが保存されていない場合はイベントバナーを表示する状態
const [isInfoOpen, setInfoOpen] = useState<boolean>(
!cookies[`sample#cookie`]
);
// 省略
// 閉じるボタンを押したときにCookieをセットして非表示にする
const closeInfo = useCallback(
(e) => {
setCookie(`sample#cookie`, new Date().toISOString(), {
path: '/',
expires: dayjs().add(20, 'year').toDate(),
});
setInfoOpen(false);
e.preventDefault();
},
[setCookie]
);
最新のコンテンツ情報が追加されたときに、過去に保存されたCookieを削除します。
Cookieに閉じるボタンをクリックした日時を保存しているので、それと最新コンテンツの日時と比較して削除を行っています。
const latestContentPublishedAt = info?.contents?.[0]?.publishedAt;
useEffect(() => {
if (latestContentPublishedAt > cookies[`sample#cookie`]) {
removeCookie(`sample#cookie`, {
path: '/',
});
setInfoOpen(true);
}
}, [cookies, latestContentPublishedAt, removeCookie]);
コンポーネント側でロジックを使用してバナーを表示させる
コンポーネント内で上記のロジックを利用します。実装の一部を掲載します。
Hooksベースで実装を行っているので、簡単に値を扱うことができます。
microCMSでは、Notification
コンポーネントを作ってそれを表示するようにしています。
const { info, isInfoOpen, closeInfo, isInfoLoading } = useInfo();
return (
<div>
{info &&
isInfoOpen &&
isInfoLoading === false && (
<a href={info.link} target="_blank" rel="noreferrer">
<Notification text={info.title} close={closeInfo}/>
</a>
)}
</div>
)
最後に
microCMSでイベントバナーを管理することで、バナーを入稿するときの実装コストが0になりました。
実際にmicroCMSでもこの仕組みを採用することで非エンジニアの方がバナーを更新する運用を行っています。
ぜひお試しください。