はじめに
この資料は、社内向け勉強会用に作られたものです。
ここ半年くらい、ReactとReact Nativeを書くお仕事していたのですが、その際ハマったことや便利だと思ったことを書き記しておこうと思います。
これから学ぶ人の参考になればと思います。
ハマリポイント
Life Cycleが多すぎてわからない。componentDidMountってなに・・・
とりあえず、LifeCycleを一気に全部覚えなくても、資料見ながらできればOKだと思う。
こちらに、綺麗にまとまっていたので、見てみよう。
参考: React component ライフサイクル図
http://qiita.com/kawachi/items/092bfc281f88e3a6e456
API取得して画面に反映したいけど、いいやり方がわからない
初心者向けの回答
( 初回呼ぶだけなら)componentWillMountでAPIをfetchしてViewに反映させるだけで良い
中級者向けの回答
- 基本的に、何かしらのイベントを経由し、データ取得する動きを目指す(side effect)
- イベント例
- componentWillMount, ボタンクリックなど
MobXを使うのであれば
MobXは、コンポーネントを跨いでstateを管理できるライブラリです。
Reduxと比べて、コード量も少なくおすすめ!
実装手順
- store内部にdata受け取り用のプロパティを用意し、
observable属性
をつける - componentWillMount, mobx-reactionなどのイベントを経由し、fetchメソッドを実行!
- fetchしたものをプロパティに格納すると、Viewに反映
mobx-reactionは大雑把に言うと、変数に付与するaddEventListenerみたいなやつ
めっさ便利。サンプル見せるのでぜひ使おう!
import { observable, reaction, action } from 'mobx';
// MobXのstore
export default class StaffIdStore {
@observable employee = {};
@observable isActive = false;
constructor() {
reaction(
() => this.isActive, // this.isActiveに変更があれば
(isActive) => { // これが発火
if (isActive && Object.keys(this.employee).length === 0) {
this.fetchData();
}
},
);
}
@action
async fetchData() {
const response = await fetch(`${config.baseUrl}/api/staff_id`)
.then((res) => (res.status === 200) ? res.json() : defaultResponse)
.catch((e) => {
console.log(e);
return defaultResponse;
});
this.employee = response.employee;
}
}
// 画面表示処理例。this.props.staffId.emploeeに変更があれば自動で更新される
@inject('staffId')
@observer
export default class StaffId extends React.Component {
render() {
return (<p>こんにちは!${this.props.staffId.employee.name}さん</p>);
}
}
ネイティブ側の機能を使うpkgを使う際の注意点
デバイス情報、カメラAPI、スプラッシュスクリーン制御などを行いたい場合、ネイティブ側を意識する必要があります。
- パッケージ選択をする際、Android, iOS両対応のライブラリを使おう!
- さぼると、if文で分岐してOS別の実装する羽目になります。
- パッケージをインストールする前に、スターの数、ライブラリの更新履歴をチェックする
- メンテされてなくて死んでる場合が多々ある
- README.mdどおりに導入しても、ビルドできなくてハマる(時がある)
- issue見ましょう。ヒントがあるかも
デバイスを識別する際は、Macアドレスを利用してはいけない
iOS8, Android6.0から、Macアドレス取得処理がプライバシー保護のため無効化された。
自分は一回実装して、破棄した…
# 動くけどダミー返される
netInfo.getMacaddress() # => '02:00:00:00:00:00'
そこで
iOSならIDFV、androidならAndroid_IDを使うのが理想かも
参考資料
端末識別は、結構難しいのでやりたければ資料に目を通そう
AndroidおよびiOSでの端末識別子について
http://qiita.com/yutao727/items/0d503c45bcbe18b27ec3#meidmobile-equipment-identifier
何もしてないのにビルドできなくなった
とりあえず、キャッシュ消そう。
# react
rm -rf node_modules && yarn && yarn start
# react native
rm -rf $TMPDIR/react-native* node_modules ios/build android/build &&
yarn && yarn start -- --reset-cache
react-native run-android
何もしてないのにビルドできなくなった
CocoaPods側もアップデート
cd ./ios
pod repo update
pod install
cd -
CocoaPods: MacOS, iOS向けのパッケージ管理ツール(npmみたいなやつ)
どうしても解決しない場合、JS側で落ちているのか、ネイティブ側で落ちてるのか見極て対処しよう。
気軽にReact Nativeのバージョンアップをすると…
気軽に死ぬ
気軽にReact Nativeのバージョンアップをすると…
とりあえず、やってみるのはいいことだとは思う
アップデートしたい場合、リリースノートをよく読んでbreaking changeを見逃さないようにしよう。
React Nativeのコアに依存してるライブラリ群が結構あるので、ひきずられて死んでないか確認必須!
やっててよかったこと
thisを使わないメソッドはlibsに切り出す
コードの粒度によるけど、jsは外部ファイル取り回しやすいので分離しとくと便利
import React from 'react';
import glamorous from 'glamorous-native';
import { palette } from '../../styles';
const { Text } = glamorous;
const boldFontSize = 16;
const boldFontWeight = '600';
export const H1 = styles =>
<Text fontSize={boldFontSize} fontWeight={boldFontWeight} color={palette.black} {...styles} />;
export const H2 = styles =>
<Text fontSize={boldFontSize} fontWeight={boldFontWeight} color={palette.darkGray} {...styles} />;
// 使い方
// import { H1 } from '../../common/libs/dom';
// <H1 textAlign="center">タイトル</H1>
ディレクトリ構成について
大きく分けて2パターン
-
垂直分割タイプ
- MVCのフレームワークとかによく使われる
-
水平分割タイプ
- 機能ごとにまとめる
- 独立した機能を作成し易い
水平分割タイプを採用
- 他から参照されない基幹部分(app)
- 他から参照される共通コード(common)
- 設定ファイル(config)
- 機能別に独立性が高いディレクトリ(それ以外)
- テストは対象ファイルと同じ階層に配置
参考
src
├── main.js // エントリーポイント
│
├── app // 他から参照されない基幹部分
│ └── components
│ │ ├── index.js // ナビゲーションとデータストアの連携
│ │ ├── AuthSwitch.js // ログイン画面とログイン後の通常画面の切り替え
│ │ ├── AppNavigation.js // ルーティング設定
│ │ └── Login.js // ログイン画面(webview)
│ ├── statics
| | ├── icon
│ │ └── SplashScreen.png
│ └── stores
│ ├── LoginStore.js
│ └── createStores.js // 各ストアのインスタンス作成
│
├── common // 他から参照される共通コード
│ ├── libs // index.js は雑多なコードが追加されやすいので作成不可
│ │ ├── auth
│ │ │ ├── digest_auth.js
│ │ │ └── index.js
│ │ └── timer.js
│ ├── stores // 他から参照されうる mobx データストア
│ │ └── AuthStore.js
│ └── styles // 共通的なスタイル設定
│ └── index.js
│
├── config // 環境によって変わる設定
│ ├── index.js // 各env を良い感じに読み込む
│ ├── env.production.js // 本番環境用設定
│ ├── env.staging.js // ステージング環境用設定
│ ├── env.testing.js // 自動テスト用上書き設定
│ ├── env.secret.js // リポジトリ管理外の機密情報, ローカル開発環境独自設定
| └── env.secret.js.release // 本番用の設定の暗号化されたファイル
│
└── Omikuji // 各機能(実在しないサンプル)
├── components // react コンポーネントを自由に配置
│ ├── index.js // TOP ページ
│ └── detail.js // 結果詳細ページ
├── libs // ライブラリを自由に配置(index.jsは何をするのかわからないので非推奨)
│ └── random.js
├── navigations
│ └── index.js // ルーティング設定
├── statics // 静的ファイルを自由に配置
│ ├── daikichi.png
│ ├── kichi.png
│ └── kyo.png
├── stores // mobx データストアを自由に配置
│ └── index.js
└── styles // スタイル設定を自由に配置
└── index.js
デバッグメニューの有効活用
iOSならCmd+D, AndroidならCmd+Mでメニューが開きます。
ロジック実装中はJS Debugging, 画面スタイル実装時はHot Reloadingを活用しよう。
react-native-debugger-open
iOS, Androidエミュレータと接続できるデバッガ。
とりあえず、入れておこう。
react-native-debugger-open - https://www.npmjs.com/package/react-native-debugger-open
まとめ
つらつらと開発中にハマったことや、やってよかったことをまとめてみました。
基盤構築の際、JS, Android, iOS領域、それぞれに地雷が埋まっており、適切に対処して行く必要があります。
初期構築する場合は、幾度となくgithubとStackOverFlowで情報収集することになると思いますので、張り切って開発しましょう!