ionic-reactことはじめとIonicでのReactライフサイクルなど

この記事は、React Advent Calendar 2019の第一日目です。

IonicでReactが使えるようになってしばらく経ちました。まだちゃんと触ったりドキュメントを終えていなかったので、ざっと動かして調べてみたまとめです。

事前準備

Node.jsのバージョンを以下のいずれか以上にしましょう。ionic startで立ち上げるテンプレートに@typescript-eslint/eslint-pluginが入っていることがあります。

こいつがNode.jsのバージョン指定をしているため、以下のバージョン以下のNode.jsを使っているとセットアップが落ちます。

  • 8.10.0以上
  • 10.13.0以上
  • 11.10.1以上

IonicのCLIを(記事執筆時点の)最新版にします。

$  npm i -g ionic@latest
updated 1 package in 15.206s

$ ionic -v
5.4.9

プロジェクトのセットアップ

早速プロジェクトを立ち上げます。今回はあえて対話式にしていますが、オプションをつけることで1発で立ち上げも可能です。

$ ionic start

Every great app needs a name! 😍

Please enter the full name of your app. You can change this at any time. To bypass this prompt next time, supply name,
the first argument to ionic start.

? Project name: YOUR_APP_NAME

FrameworkをReactにする

プロジェクト名を指定すると、フレームワークが選べます。ここはおそらく将来的に他のフレームワークも出てくるのでしょう。


Pick a framework! 😁

Please select the JavaScript framework to use for your new app. To bypass this prompt next time, supply a value for the
--type option.

? Framework: 
  Angular | https://angular.io 
❯ React   | https://reactjs.org

テンプレートを指定する

続いてテンプレートを指定します。blankで一から作るのも良いですが、今回はあえてconferenceでがっつり作ってあるやつを選んでみます。

Starter templates are ready-to-go Ionic apps that come packed with everything you need to build your app. To bypass this
prompt next time, supply template, the second argument to ionic start.

? Starter template: 
  blank      | A blank starter project 
  sidemenu   | A starting project with a side menu with navigation in the content area 
  tabs       | A starting project with a simple tabbed interface 
❯ conference | A kitchen-sink application that shows off all Ionic has to offer 

ちなみにここで以下のエラーが出た場合は、Node.jsのバージョンが古いです。 Nodeのバージョンをアップデートしたのち、cd YOUR_APP_NAME && yarnを実行してリトライしてやりましょう。

error @typescript-eslint/eslint-plugin@2.9.0: The engine "node" is incompatible with this module. Expected version "^8.10.0 || ^10.13.0 || >=11.10.1". Got "10.5.0"
error Found incompatible module.
info Visit https://yarnpkg.com/en/docs/cli/install for documentation about this command.
[ERROR] An error occurred while running subprocess yarn.
        
        yarn install --non-interactive exited with exit code 1.
        
        Re-running this command with the --verbose flag may provide more information.

こっちのメッセージが出たら準備完了です。

INFO] Next Steps:
       
       - Go to your cloned project: cd ./YOUR_APP_NAME
       - Run ionic serve within the app directory to see your app
       - Build features and components: https://ion.link/scaffolding-docs
       - Run your app on a hardware or virtual device: https://ion.link/running-docs

Ionic Reactアプリをローカル起動する

続いてローカル起動させてみましょう。

$ cd ./YOUR_APP_NAME
$ ionic serve
> react-scripts start
[react-scripts] Starting the development server...

わかる人にはわかるやつですが、react-scriptsが出てくるということは、Ionic Reactはcreate-react-appを使ってセットアップされています。ちなみにドキュメントにもそう書かれていました

localhostのURLが出てこない場合

conferenceのtemplateですが、この記事をかいている時点だと、ionic serveでlocalhostの何番で起動したかがわからなくなっています。

> react-scripts start
[react-scripts] Starting the development server...
[react-scripts] 
[react-scripts] Compiled with warnings.
[react-scripts] 
[react-scripts] ./src/components/SessionListItem.tsx
[react-scripts]   Line 1:25:  'useState' is defined but never used  @typescript-eslint/no-unused-vars
[react-scripts]   Line 2:26:  'IonAlert' is defined but never used  @typescript-eslint/no-unused-vars
[react-scripts] ./src/data/connect.tsx
[react-scripts]   Line 1:29:  'useEffect' is defined but never used                                                                                                                                                                                                   @typescript-eslint/no-unused-vars
[react-scripts]   Line 1:40:  'useState' is defined but never used                                                                                                                                                                                                    @typescript-eslint/no-unused-vars
[react-scripts]   Line 39:8:  React Hook useMemo has a missing dependency: 'context'. Either include it or remove the dependency array. Outer scope values like 'mapDispatchToProps' aren't valid dependencies because mutating them doesn't re-render the component  react-hooks/exhaustive-deps
[react-scripts]   Line 44:8:  React Hook useMemo has a missing dependency: 'dispatchFuncs'. Either include it or remove the dependency array                                                                                                                          react-hooks/exhaustive-deps
[react-scripts] ./src/pages/SchedulePage.tsx
[react-scripts]   Line 9:25:  'addFavorite' is defined but never used     @typescript-eslint/no-unused-vars
[react-scripts]   Line 9:38:  'removeFavorite' is defined but never used  @typescript-eslint/no-unused-vars
[react-scripts] Search for the keywords to learn more about each warning.
[react-scripts] To ignore, add // eslint-disable-next-line to the line before.

ESLintのwarningが先に出てきてしまっているという状態ですね。内容に合わせて修正すればOKではあります。

本来はIssueなりPR出したりしないとかなと思いつつ、カレンダーに間にあわせるためにとりあえずここに書いてます。後でやります。

もしURLが出てこない場合は、https://localhost:8100/tutorialを試してみてください。自分の場合はこれでいけました。

Ionic Reactには独自のライフサイクルがある

Reactであれば通常component[Did | Will]XXXuseXXXというライフサイクルメソッドを使います。Ionicの場合、これらのIonic版が用意されていますので、こちらを使うことになります。

  • ionViewWillEnter コンポーネントが表示されるアニメーションがはじまる時に発火します。
  • ionViewDidEnter コンポーネントが表示されるアニメーションが終了した時に発火します。
  • ionViewWillLeave コンポーネントを離脱するアニメーションがはじまる時に発火します。
  • ionViewDidLeave コンポーネントを離脱するアニメーションが終了した時に発火します。

from: https://ionicframework.com/jp/docs/react/lifecycle

React側で非推奨になったcomponentWillMount的に使えそうなメソッドがあるのが目につきますね。

Tips: ionViewWillEnterはcomponentDidMount相当

ぱっと見componentWillMountを使っちゃってるのかなと思えますが、実装をみるcomponentDidMountにいるっぽいです。

詳しく追いきれていませんが、Reactのライフサイクル -> Ionicのライフサイクルになるイメージでしょうか。

Ionic Reactでは、なるべくIonicのライフサイクルを利用しよう

ドキュメントにも記載されていますが、React側のライフサイクルを使うと、意図しない動きになることがある様子です。

ただし、Ionic Reactはページのライフタイムを管理するため、特定のイベントが期待どおりに発生しない場合があります。 たとえば、最初にページが表示されたときは componentDidMount が起動しますが、ページから移動した時にIonicはページをDOMツリーに保持しているため、その後の当該ページへのアクセスでは componentDidMount を再度呼び出さない場合があります。 

https://ionicframework.com/jp/docs/react/lifecycle

Reactのライフサイクルも使えるが、なるべくIonic側のライフサイクルにのる必要がありそうです。

Comment