React で LIFF (LINE Front-end Framework) v2 を使ってみる

[react-liff](https://www.npmjs.com/package/react-liff) という npm package を作ってみたので、その使い方の紹介です。
デモアプリは [こちら](https://liff.line.me/1654340399-ME0xEG8k) で公開しています。

## 2020/07/10 追記
LIFF SDK が（試験的に） npm package として公開されました。
https://developers.line.biz/ja/docs/liff/release-notes/#liff-sdk%E3%82%92npm%E3%83%91%E3%83%83%E3%82%B1%E3%83%BC%E3%82%B8%E3%81%A8%E3%81%97%E3%81%A6%E5%85%AC%E9%96%8B%E3%81%97%E3%81%BE%E3%81%97%E3%81%9F

それに伴い、`node_modules` からの LIFF SDK 読み込みに対応した、react-liff version 0.5.0 を公開しました。
使い方は [こちら](https://github.com/epaew/react-liff/tree/master#when-you-use-npm-version-of-liff-sdk-recommended) をご覧ください。

## 2020/06/15 追記
version 0.4.0 をリリースしました。ログイン状態を `useState()` で管理できるようになったので、
さらに使い勝手が良くなったと思います。
サンプルを、新APIを使ったものに差し替えました。

## 使い方
### CRA で React SPA の開発環境を作る
```sh
npx create-react-app react-liff-sample
```

### react-liff を依存関係に追加する
```sh
cd react-liff-sample
yarn add react-liff
```

---

### public/index.html で、LIFF SDKを読み込む
```diff
     <title>React App</title>
+    <script defer charset="utf-8" src="https://static.line-scdn.net/liff/edge/versions/2.1.13/sdk.js">
   </head>
```

### src/index.js に LiffProvider を追加する
```diff
 import React from 'react';
 import ReactDOM from 'react-dom';
 import './index.css';
 import App from './App';
 import * as serviceWorker from './serviceWorker';
 
+import { LiffProvider } from 'react-liff';
+
+const liffId = process.env.LINE_LIFF_ID ?? '';
+const stubEnabled = process.env.NODE_ENV !== 'production';
+
 ReactDOM.render(
   <React.StrictMode>
-    <App />
+    <LiffProvider liffId={liffId} stubEnabled={stubEnabled}>
+      <App />
+    </LiffProvider>
   </React.StrictMode>,
   document.getElementById('root')
 );
```

### src/App.js に useLiff を追加する
```diff
-import React from 'react';
+import React, { useEffect, useState } from 'react';
 import logo from './logo.svg';
 import './App.css';

+import { useLiff } from 'react-liff';
+
 function App() {
+  const [displayName, setDisplayName] = useState('');
+  const { error, liff, loggedIn, ready } = useLiff();
+
+  useEffect(() => {
+    if (!loggedIn) return;
+
+    (async () => {
+      const profile = await liff.getProfile();
+      setDisplayName(profile.displayName);
+    })();
+  }, [liff, loggedIn]);
+
+  const showDisplayName = () => {
+    if (error) return <p>Something is wrong.</p>;
+    if (!ready) return <p>Loading...</p>;
+
+    if (!loggedIn) {
+      return <button className="App-button" onClick={liff.login}>Login</button>;
+    }
+    return (
+      <>
+        <p>Welcome to the react-liff demo app, {displayName}!</p>
+        <button className="App-button" onClick={liff.logout}>Logout</button>
+      </>
+    );
+  }
+
   return (
     <div className="App">
       <header className="App-header">
         <img src={logo} className="App-logo" alt="logo" />
-        <p>
-          Edit <code>src/App.js</code> and save to reload.
-        </p>
+        {showDisplayName()}
         <a
           className="App-link"
           href="https://reactjs.org"
```

### LIFF アプリをチャネルに追加する
実際に動かして見るためには、`LIFF ID` が必要になるので、
[LIFFアプリをチャネルに追加する](https://developers.line.biz/ja/docs/liff/registering-liff-apps/)
を参考に、LIFF アプリを追加します

### デプロイする
`HTTPS` が有効で、公開されているサーバーならどこでも良いです。
Firebase Hosting, GitHub Pages, AWS S3 あたりが手軽で良いと思います。
GitHub Pages にデプロイするなら、https://github.com/peaceiris/actions-gh-pages を使うと便利です。

### 動作確認
LINEから、デプロイしたページにアクセスすると、自動ログインのあとにLINEの表示名が表示されます。
（以下のキャプチャはローカル環境で実行したときのものなので、stub の返り値が表示されています。）

![CreateReactLIFFApp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260472/849c3898-cd1a-beff-aaef-cce983cdfca9.png)

## 最後に
npm package を公開してから、こんな Tweet を見つけました。。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">LIFFをReact + TypeScriptで開発するための公式npmモジュールが出るらしい。(From LINE Dev Day)<a href="https://twitter.com/hashtag/LINE_API?src=hash&amp;ref_src=twsrc%5Etfw">#LINE_API</a> <a href="https://twitter.com/hashtag/serverless?src=hash&amp;ref_src=twsrc%5Etfw">#serverless</a> <a href="https://twitter.com/hashtag/AWS?src=hash&amp;ref_src=twsrc%5Etfw">#AWS</a> <a href="https://twitter.com/hashtag/LINE_API_XTECH?src=hash&amp;ref_src=twsrc%5Etfw">#LINE_API_XTECH</a></p>&mdash; あき@プピャオ (@maccostar) <a href="https://twitter.com/maccostar/status/1225370294291857409?ref_src=twsrc%5Etfw">February 6, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

早く公開されるといいですね！；_；
以上です

## 参考
* https://developers.line.biz/ja/docs/liff/
* https://developers.line.biz/ja/reference/liff/