はじめに
タイトルに「React経験者」とは書きましたが、私自身1つWebアプリを開発したぐらいなので、そこまでマスターしているわけではありません。(なんか、すみません...)
その React のアプリを作ったときに、これスマホアプリにしたら良くないか?と思って、React Native とかいうのあったよなと思って、始める前は React と React Native って名前似てるから、Reactのコードを使ってアプリを作れるのかと思ったんです。
でも、Reactと同じ書き方ができる少し違う別物みたいなものだということが分かりました。
この結論に辿り着くのに少し時間がかかったので、React やったことがある人で「React Native に興味あるよ〜」みたいな人向けに React Native を使ってアプリを作った上で感じた React や Web 開発との違いをイメージできるような記事を作ろうと思いました。
本記事は、チュートリアルや環境構築のやり方ではなく、ただただ私が感じた違いを書いてるだけです。違いの他にも感想やこれから始める方への簡単なアドバイスも載せてます。
追記するものがあったらする予定です。
いろいろな違い
タグ
タグの違いは以下のような感じです。
| React Native | Web | 用途 |
|---|---|---|
| View | div | レイアウトなど |
| Text | p, span | 文字表示 |
| ScrollView | overflow-y: autoに設定したdivなど | スクロールさせる |
| TextInput | input | 入力フォーム |
| Pressable / Button | button | ボタン |
こう見るとただ置き換えれば良いように感じますが、例えば Pressable の場合は
<Pressable
style={shadowStyles.shadow}
onPress={() => {
setTrigger(1);
}}
>
<Text>はじめる</Text>
</Pressable>
のようにします。
Pressable にはクリック判定しかないので、文字部分は別途で Text を使う必要があります。逆にこれの便利なところは「ポップアップ外の部分をタッチしたときにポップアップを閉じる」みたいな仕様を作る場合、透明なタッチ判定として Pressable をポップアップの後ろに配置できるので Web における
{
position: 'absolute',
top: 0,
right: 0,
bottom: 0,
left: 0,
}
と同じ効果のある
style={StyleSheet.absoluteFill}
を使うことで親要素全体に配置させてあげれば簡単に実装できます。
ボタンには Button というものもありますが、これはスタイルの変更がほぼ不可能なので使わない方が良いです。
使うときが面倒で、毎回インポートする必要があります。
import {
Pressable,
ScrollView,
Text,
View,
} from "react-native";
アニメーションが楽
ここでは詳しく説明しませんが、
import { Animated } from "react-native";
これを使うだけで簡単に点滅のアニメーションなどを作ることができます。
ロード表示のぐるぐるが恐ろしく簡単に導入可能
ロード表示でぐるぐるのアニメーションが使いたいことってよくあると思うのですが、
import { ActivityIndicator } from "react-native";
をして、ActivityIndicatorを配置するだけで良いという。
わざわざBootStrapなどに頼らなくても React Native に標準搭載されているのが最強です。
ただ iOS と Android で表示が異なるのでご注意ください。
BootStrapなどが使えない代わりに...
BootStrapなどはタグが違うので使えません。
そこで使えるのが
この Expo 公式のアイコン集。インポートのコードまで載っているのでこれを使うと良いです。
ただ、ロードに時間がかかるので
// アイコンの読み込み管理
const [iconLoaded] = useFonts({
...Feather.font,
...Octicons.font,
...AntDesign.font,
});
if (!iconLoaded) {
return <LoadingScreen />;
}
のようにしてロード表示を入れると良いです。
CSSが違うけど便利なところも
import { StyleSheet } from "react-native";
で StyleSheet を入れると以下のような書き方ができます。
(入れなくてもstyleに直接書けば使えます。)
書き方
const styles = StyleSheet.create({
btn: {
marginHorizontal: 10,
alignItems: "center",
justifyContent: "center",
paddingHorizontal: 10,
paddingVertical: 4,
borderRadius: 12,
},
text: {
fontSize: 20
},
});
のように const の変数として宣言します。見ると分かると思うのですが、CSSにかなり似ていますよね。これを下のようにstyleの中に書いて適用します。
<Pressable
onPress={() => {
setScreen(!isScreen);
}}
style={styles.btn}
>
<Title />
</Pressable>
ちなみにstyleに複数設定する場合は配列を使います。
style={[styles.btn, { backgroundColor: 'white' }]}
const で宣言するので、用途ごとにconst shadowStylesやconst gameStylesのように分けることができるので便利です。
関数が入れられる
Pressable の場合は pressed というのがあり、
style={({ pressed }) => [
styles.btn,
!pressed && shadowStyles.shadow,
pressed && shadowStyles.shadow_pressed,
]}
のように取得することでクリック状態に応じて適用させるスタイルを分岐させることができます。
変数を組み込める
function createStyles(lenX: number, lenY: number) {
return StyleSheet.create({
board_container: {
alignItems: "center",
justifyContent: "center",
backgroundColor: "rgb(50, 50, 50)",
padding: 2,
width: lenX + 10,
height: lenY + 15,
marginTop: 10,
},
});
}
このように関数と組み合わせることで変数を使うことができます。
ぼやけ表示が簡単
ポップアップの背景をぼやかせたいときに使えるのが、
import { BlurView } from "expo-blur";
です。
なんと、
<BlurView intensity={15} tint="dark" style={StyleSheet.absoluteFill} />
これだけでぼやかすことができます。
QR発行とスキャナ機能の実装がとても簡単
Web 開発で QR コード関連の実装をしようとすると外部のライブラリを読み込んで少し複雑なコードで実装すると思うのですが、React Native の場合は
import QRCode from "react-native-qrcode-svg";
<QRCode value={qrCodeValue} size={size} />
これだけで実装可能です。
スキャナは
import { CameraView, useCameraPermissions } from "expo-camera";
でカメラを使用できるようにして、
const [permission, requestPermission] = useCameraPermissions();
useEffect(() => {
if (!permission) {
requestPermission();
}
}, [permission]);
でカメラのアクセス許可を取って、
<CameraView
barcodeScannerSettings={{
barcodeTypes: ["qr"], // ← QRに限定
}}
onBarcodeScanned={}
/>
を使うことで実装できます。
面白いと感じたこと
index.htmlがないのにJavaScriptを書いているところ
Webアプリだけではなく、ネイティブアプリが作れるので当たり前と言えば当たり前ですが、htmlファイルが一つもないのが面白かったです。Reactの場合でも.jsxや.tsxを編集することが多いと思いますが、index.htmlはいると思います。
デバイスのダークモードを認識できるように設定可能なところ
私は使いませんでしたが、デバイスのダークモード設定を取得できます。ダークモードの設定で条件分岐させて UI を設計できるので面白いと思いました。
OSの通知機能が利用可能
これも使ったことありませんが、OS の通知機能が使えます。いつか使ってみたいですね。
面倒なところ
Apple製品とAndroidの仕様の違い
おそらく Web 開発で誰もが一度はぶつかるであろう OS の違いによる細かい仕様の差。これは React Native でもあります。
スマートフォンとタブレットの認識
iPhone と iPad 向けのアプリ開発の場合、iPad ユーザーなら分かるかもしれませんが、iPad に対応させるかどうかを設定できます。つまり、iPadでも開けるけどiPhoneサイズの画面になるよっていう設定です。
これはapp.jsonというファイルで
"ios": {
"supportsTablet": false
}
と設定するだけ。trueにすれば iPad にも正式対応させることができます。
めちゃくちゃ便利ですよね!
でもAndroidはそう簡単にはいきません...
なんと Android スマホとタブレットの区別がつけられないんです。そのため、画面サイズで条件分岐するしかありません。
影の表現
Apple 製品の場合は影の色をつけることで影を表現しますが、Android の場合は実際に浮かせます。(逆に Apple 製品では浮かせられず、Android では影の色をつけることができません。)
shadow: {
backgroundColor: "#f8f8f8", //共通
shadowColor: "#757575", //Apple
shadowOffset: { //Apple
width: 2,
height: 4,
},
shadowOpacity: 0.35, //Apple
shadowRadius: 3.84, //Apple
elevation: 15, //Android
opacity: 1, //共通
},
例えば、私のコードだとこんな感じです。Android ではどのくらい浮かせるかというのelevationという値で設定するだけなので簡単な反面、影の色や大きさなどが自由に設定できないのが不便なところです。
フォントサイズ
(少なくとも私の iPhone と Android の実機だと、) 同じフォントサイズでも iPhoneの方が Android より小さく表示されます。同じサイズにしようとすると大体 +2〜4 くらいのズレが発生します。
AsyncStorageの容量の違い
import AsyncStorage from "@react-native-async-storage/async-storage";
これで使えるようになるAsyncStorageというデバイスのローカルにデータを保存できるものがあるのですが、Androidは意外とすぐに容量オーバーでエラーが発生します。(デバイスのストレージは十分にあり、Expo Goアプリで発生しました。) 今のところ iOS でこのエラーにあったことはありませんが、もしかしたら iOS にもあるかもしれませんがエラーは発生のラインが明らかに違うことは分かります。
また、このエラーがExpo Goアプリによるものなのかは分かりません。
この辺に詳しい方がいましたら教えてください。
救いはある
下のように React Native が提供している Platform を使うことで OS ごとの設定を行うことができます。
const textStyle = StyleSheet.create({
text_style: {
...Platform.select({
ios: {
fontSize: 16,
},
android: {
fontSize: 14,
},
}),
}
});
スライダーやドロップダウンなどは別途でインストールが必要な場合がある
一部のコンポーネントは標準の React Native にないので追加で入れる必要があることです。
スライダの場合だと、
npx expo install @react-native-community/slider
でインストールして
import Slider from "@react-native-community/slider";
でインポートして使用します。
ドロップダウンはよりクセがある
ドロップダウンにはいくつか種類があるのですが、私は Picker と RNPickerSelect を試しました。なぜか Picker だと iOS での表示が崩壊するのでRNPickerSelectが良いです。ただ、RNPickerSelect の場合でもOSによる若干の表示差異は発生します。
React Nativeを始める上でのアドバイス
Expo Goは絶対に使った方が良い
React Native でネイティブアプリを開発する場合でも Web アプリを開発する場合でもExpo Goが便利です。
実行用のサーバーを立ててそこに実機やシミュレーターを繋ぐことで実行するのですが、キー1つで Web サイトを開いたりリロードしたりでき、実機の場合は発行されるQRコードを読み取って Expo Go 内で開くだけで実行できるのでとても楽です。
ビルドも Expo でできるのですが、無料アカウントの場合は1ヶ月のビルド回数に制限があるので注意してください。
GoogleFontsを使うのも簡単
npx expo install expo-font
npx expo install @expo-google-fonts/noto-sans-jp
こんな感じでやれば簡単に組み込めます。
※ ライセンスには注意してください。
注意点
- OSごとでExpo Go アプリの仕様が異なる
Expo Goアプリには以下のような違いがあります。
- Android で使える画面上に常駐できるデバッグツール(リロードボタンなどがある)が iOS 版にはない
- 立てたサーバーの QR コードを読み取るときに Android の場合は Expo Go アプリ内にある QR コードスキャナで読み取ればいいのですが、iOS の場合は普通にカメラアプリで読み取る必要があります
- Expo Go と Expo でビルド版で表示に若干差異が発生すること
例えば、RNPickerSelect で作ったドロップダウンの中の文字の色が Expo Go で実行した場合は文字の色を設定していなくても黒色になりましたが、ビルドしたものは白色に表示されていました。 - ビルドしたアカウントでログインしなくても、ビルド済みのアプリはインストール可能
おわりに
パッと思いついたものを挙げてみました。最初に書いた通り、書き忘れや新しい発見があったら追記しようかなと思ってます。
色々書きましたが、React を理解していれば簡単にネイティブアプリを開発できるので、迷っている場合は挑戦してみるのも良いと思います!