どもども!今回は、LIFF(LINE Front-end Framework)アプリケーションをReactで開発する際の初期開発のセットアップを行いました。SWRとreact-error-boundayのエラーハンドリングとLIFFから情報を取得する部分をHooksとしてまとめておきました。LIFFを運用するために必要な設定なので、是非ご一読!
はじめも
どもども!本日三台目の救急車が家の前を通りすぎている龍ちゃんです。メイン通りから一本入ったところなんですけど、病院が近いこともあって救急車は大量に通ります。この辺は、住んでからじゃないとわからないところですね。さて…いろんなことが同時並行で進んでいるので、頭がパンクしないか不安に駆られています。
さて、今回もLINEのLIFF(LINE Front-end Framework:以降LIFF)に関する内容になります。前回は、LIFFアプリケーションの開発環境構築について記事にしました。今回の記事では、もっとフロントエンド寄りの内容について書いていきます。デフォルトのアプリケーションから、実際の開発スタイルに寄せていきます。
今回対応した内容としては、以下になります。
- LIFFアプリケーションのエラーのエラーハンドリング
liff.init
をコンポーネントとして分離する
- LINE内のブラウザ以外で起動した場合は、LINEに誘導をする
- LIFFアプリケーションで取得することができる情報をHooksにまとめる
- SWRを用いてLINEログイン者情報を取得する
それでは、順番に取り組んでいきたいと思います。こちらの記事は、2つの記事をベースに構成されています。
LIFFアプリのカスタマイズ
今回は、以下のディレクトリ構造で取り組んでいきます。
src/
├── App.tsx
├── hooks
│ └── useAuth.ts
├── index.css
├── main.tsx
├── pages
│ ├── NotfoundPage.tsx
│ ├── TopPage.tsx
│ └── layouts
│ └── ParentLayout.tsx
├── router
│ └── RouterConfig.tsx
├── utilities
│ ├── ErrorBoundary.tsx
│ ├── LiffInit.tsx
│ └── SwrConfig.tsx
└── vite-env.d.ts
必要なライブラリとしては、以下になります。必要に応じてインストールしてください。
# ReactでSPAにするために
yarn add react-router-dom
# データフェッチ用ライブラリ
yarn add swr
# エラーハンドリング
yarn add react-error-boundary
LIFFアプリケーションのエラーハンドリング
LIFFアプリケーションのハンドリングを行うための設定を行います。まずは、コンポーネント設計を図にしたのでおいておきます。
今回は、react-error-boundaryを用いてエラーを一元管理しています。utilities
内のErrorBoundary.tsx
の内容が以下になります。
import { ErrorBoundary, FallbackProps } from "react-error-boundary";
type Props = {
children: React.ReactNode;
};
export const ErrorBoundaryComponent = (props: Props) => {
const { children } = props;
return (
<ErrorBoundary FallbackComponent={ErrorFallback}>{children}</ErrorBoundary>
);
};
const ErrorFallback = ({ error, resetErrorBoundary }: FallbackProps) => {
console.error(error);
return (
<>
<button className="" onClick={resetErrorBoundary}>
リトライ
</button>
</>
);
};
データ取得はSWRを用いた管理をするため、SWRのエラーをreact-error-bounday
に伝搬させる必要があります。同じくutilites
内のSwrConfig.tsx
の内容が以下になります。
import { useErrorBoundary } from "react-error-boundary";
import { SWRConfig } from "swr";
type Props = {
children: React.ReactNode;
};
export const SWRConfigComponent = (props: Props) => {
const { children } = props;
const { showBoundary } = useErrorBoundary();
return (
<SWRConfig
value={{
onError(err) {
showBoundary(err);
},
}}
>
{children}
</SWRConfig>
);
};
react-error-bounday
が提供しているuseErrorBoundary()
を使用してSWRでキャッチしたエラーを伝搬させます。
import { useErrorBoundary } from "react-error-boundary";
const { showBoundary } = useErrorBoundary();
showBoundary(err);
こちらのHooksを呼び出すことで、任意のタイミングでエラー画面へ遷移させることが可能になります。
最後に、LIFFアプリケーションのセットアップ用の構築を行います。同じくutilites
内のLiffInit.tsx
の内容が以下になります。
import liff from "@line/liff";
import { useEffect, useState } from "react";
import { useErrorBoundary } from "react-error-boundary";
type Props = {
children: React.ReactNode;
};
export const LiffInit = (props: Props) => {
const { children } = props;
const { showBoundary } = useErrorBoundary();
const [liffInit, setLiffInit] = useState<boolean>(false);
const isInLineClient = liff.isInClient();
useEffect(() => {
liff
.init({
liffId: import.meta.env.VITE_LIFF_ID,
})
.then(() => {
setLiffInit(true);
console.log("LIFF init succeeded.");
})
.catch((e: Error) => {
setLiffInit(false);
showBoundary(e);
});
});
if (!liffInit) {
return <>Loading now</>;
}
if (!isInLineClient) {
return <>Please open in LINE ここでQRの画像を出すのはありでは?</>;
}
return <>{children}</>;
};
こちらでは、LIFFアプリケーションの初期化を行っています。初期化が失敗した場合は、SWRの場合と同じくreact-error-bounday
が提供しているuseErrorBoundary()
を使用してエラーを伝搬させます。あとは、以下のファイルをlayout
として保存します。
import { Outlet } from "react-router-dom";
import { ErrorBoundaryComponent } from "@utilities/ErrorBoundary";
import { LiffInit } from "@utilities/LiffInit";
import { SWRConfigComponent } from "@utilities/SwrConfig";
export const ParentLayout = () => {
return (
<>
<section className="">
<main>
<ErrorBoundaryComponent>
<SWRConfigComponent>
<LiffInit>
<Outlet />
</LiffInit>
</SWRConfigComponent>
</ErrorBoundaryComponent>
</main>
</section>
</>
);
};
これによって、Outlet内で発生したReactのエラーはreact-error-bounday
に吸収され、SWRとLIFFセットアップのエラーも同様に吸収されます。使用方法としては、react-router-domで構成しているConfigファイルでトップとしてParentLayout.tsx
を設定することで機能します。
LINE内のブラウザ以外で起動した場合は、LINEに誘導をする
こちらは、ライブラリに搭載されている。liff.isInClient()
を使用して実装することができます。公式ドキュメントはこちらにあります。こちらの値がTrueの場合は、LINE内部ブラウザになります。
utilites
内のLiffInit.tsx
内で表示を切り替えることで、外部ブラウザからのアクセスの場合は、QRやLINEアカウントへのリンクを表示することで「LINE内部ブラウザで起動した場合は、LINEに誘導する」ことができます。
LIFFアプリケーションで取得することができる情報をHooksにまとめる
ここでは、情報取得や内部で使いまわしそうな情報をHooksにまとめていきたいと思います。データの取得部分をSWR経由で取得しています。
import liff from "@line/liff";
import useSWRImmutable from "swr/immutable";
export const useAuth = () => {
const accessToken = liff.getAccessToken();
const idToken = liff.getIDToken();
const { data: profile, isLoading: isProfileLoading } = useSWRImmutable(
"liff/profile",
() => liff.getProfile()
);
return { accessToken, idToken, profile, isProfileLoading };
};
アクセストークンとIDトークンを取得しておきます。これは、サーバー側でLINEの情報をセキュアに運用するために必要となる情報です。
profile
内には以下の情報が含まれます。
- userId:ユーザーID
- displayName:表示名
- pictureUrl:画像のUrl
- statusMessage:ステータスメッセージ
こちらは、LINE内で設定している情報になります。その一方で、こちらの情報はサーバーに送信することが公式から止められています!!そのために必要となるのが、アクセストークンとIDトークンになります。
おわりも
ども!今回は、LIFFのアプリケーションの初期開発としてエラーハンドリングやHooksの設定を行いました。エラーハンドリングなどは、一番最初に設定するべきです。でも、開発を進めていかないと気付くことができないものですよね。やっぱりフロントエンドの開発は難しいですね。
これからは、LIFFアプリの情報をちょこちょこっと投稿していきます。
Twitterのほうもよろしくお願いします。