LIFFをNext.jsなどで使いやすくするHookライブラリ’use-line-liff’をリリースしました

npm: https://www.npmjs.com/package/use-line-liff
GitHub: https://github.com/hideokamoto/use-line-liff

背景

Next.jsでLIFF SDKを利用する場合、SSRでの実行を避ける処理が必要です。これは、LIFF SDKがおそらく内部でwindow変数を利用しているため、window is not definedエラーが発生することが原因です。

そのため、LINE公式のサンプルなどでは、useEffectpagePropsを利用する方法が紹介されています。

/**
 * @see https://github.com/line/line-liff-v2-starter/blob/master/src/nextjs/pages/_app.js
 **/
function MyApp({ Component, pageProps }) {
  const [liffObject, setLiffObject] = useState(null);
  const [liffError, setLiffError] = useState(null);

  // Execute liff.init() when the app is initialized
  useEffect(() => {
    // to avoid `window is not defined` error
    import("@line/liff").then((liff) => {
      console.log("start liff.init()...");
      liff
        .init({ liffId: process.env.LIFF_ID })
        .then(() => {
          console.log("liff.init() done");
          setLiffObject(liff);
        })
        .catch((error) => {
          console.log(`liff.init() failed: ${error}`);
          if (!process.env.liffId) {
            console.info(
              "LIFF Starter: Please make sure that you provided `LIFF_ID` as an environmental variable."
            );
          }
          setLiffError(error.toString());
        });
    });
  }, []);


  // Provide `liff` object and `liffError` object
  // to page component as property
  pageProps.liff = liffObject;
  pageProps.liffError = liffError;
  return <Component {...pageProps} />;
}

ただ、個人的にはStripe SDKのように「useXXXでクライアントのインスタンスを取得して、undefinednullでなければロード完了している」パターンの方が使いやすいので、React Hookにしてみました。

use-line-liffの使い方

一般的なReact Hookライブラリ(Provider付き)なので、インストールして使うだけです。

% npm install use-line-liff

Next.jsの場合、pages/_app.jsまたはpages/_app.tsxにProviderを追加します。

import { LiffProvider } from 'use-line-liff';

function MyApp({ children }) {
   return (
     <LiffProvider liffId={process.env.NEXT_PUBLIC_LIFF_ID}>
       {children}
     </LiffProvider> 
  );
};

export default MyApp;

あとはuseLiffフックを使ってLIFF SDKクライアントを取得するだけです。

import { useEffect } from 'react';
import { useLiff } from 'use-line-liff';

const Home = () => {
  const { liff } = useLiff();
  useEffect(() => {
    if (!liff) return;
    if (!liff.isLoggedIn()) {
      liff.login();
    }
    liff.getProfile();
...

Mockを使う

LIFF Mockがローカル開発で便利そうでしたので、バンドルしてみました。

Providerでオンオフの設定ができます。

import { LiffProvider } from 'use-line-liff';

function MyApp({ children }) {
   return (
     <LiffProvider
       liffId={process.env.NEXT_PUBLIC_LIFF_ID}
       mock={{
         enable: true,
       }}
     >
       {children}
     </LiffProvider> 
  );
};

export default MyApp;

ロード後にモックの中身を書き換えることも可能です。

function MyApp({ Component, pageProps }: AppProps) {
    return (
      <LiffProvider
        liffId={process.env.NEXT_PUBLIC_LIFF_ID as string}
        mock={{
          enable: true,
          mockDidLoaded: (p) => {
            return {
              ...p,
              getProfile: {
                  ...p.getProfile,
                  userId: 'custom-user-id'
              }
            }
          }
        }}
      >
      <Component {...pageProps} />
      </LiffProvider>
    )
  }

実運用では、process.envあたりで「ローカルの時だけモックを有効にする」ような使い方ができるかなと思います。

mockenable: falseの場合、mockDidLoadedは動きませんので、こちらまで分岐を書く必要はない(はず)です。

今後について

LINE(LIFF)は触り始めたばかりなので、これの開発の前に「これを使ったLIFFアプリ」をリリースしたいなと思っています。その中で欲しくなった機能があれば、少しずつ追加していく予定です。

Inspectorの方もサポートすると便利そうだなー」とか、「中の人的には、Stripeのプラグインも入れたいなぁ」とか、妄想は広がるばかりですが。。。

あとは・・・Gatsbyプラグインとかかなぁ・・・

Comment