Open3

React Native学習日記

つ

環境構築してみる

下記を参考にする
https://qiita.com/nskydiving/items/41e446ef5c821359ab79

二つの開発ツールがある

  • React Native CLI
    • 以前挫折した(環境構築)
    • 最初はこっちの方がおすすめらしいので環境構築してみる
  • React Native Expo
    • ちょっと触ったことあるけどお手軽な印象

React Native CLIの環境構築

HomeBrewを使ってインストールしようとするが、HomeBrewがない

HomeBrewのインストール

下記を参考にする。
https://lanchesters.site/brew-commnad-not-found/

インストールコマンドを実行。

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
Homebrew is not (yet) supported on ARM processors!
Rerun the Homebrew installer under Rosetta 2.
If you really know what you are doing and are prepared for a very broken
experience you can use another installation option for installing on ARM:
  https://docs.brew.sh/Installation

HomeBrewをインストールするにも問題がある模様、調査してみる

https://qiita.com/shira-shun/items/0f6213f4923cb5544367

Macの世代によって上記のコマンドが使えないだとかなんとか(適当)
terminalについて、Rosettaを使用して開く、という風な設定を行う。

https://oku.edu.mie-u.ac.jp/~okumura/macosx/m1.html

FinderからTerminalを検索⇨右クリック⇨情報を見る
で、「Rosettaを使用して開く」にチェック。
その後Terminalを再起動し、HomeBrewのインストールコマンドを再度実行。

無事にインストールできたので、再度ReactNative CLIのインストール。

$ brew install node
$ brew install watchman

CocoaPodsとやらもインストール

$ sudo gem install cocoapods

iOSシミュレータも無事起動したので、ReactNativeプロジェクトを立ち上げてみる

npx react-native init AwesomeProject

下記のエラー。。。

Error: Failed to install CocoaPods dependencies for iOS project, which is required by this template.

なんやかんやエラー内容を調査し下記リンクが関係しそうなので対応。
https://hisasann.github.io/2020/02/13/first-time-react-native/

pod installを実行。
ようやくiOSプロジェクトを起動しようとしたが下記のエラー。

Failed to construct transformer:  DuplicateError: Duplicated files or mocks. Please check the console for more info

...なんか色々うまくいかないので一旦AwesomeProjectを削除

rm -rf AwesomeProject

node,watchmanのインストールは出来てるので、下記参考に進めたらようやくiOSプロジェクトが起動できた。
https://qiita.com/takaishota/items/4db36a806a257582fa1f

つ

Udemy講座体験記

ニュースアプリを作りながら学べるUdemyの講座を受講
https://www.udemy.com/course/react-native-first-step/

簡単な流れは下記(実施した範囲だけ)

  • Expoのインストール
  • 実機のアプリデバッグ
  • Expoのメリット・デメリットについて
  • UI作成
  • コンポーネント化
  • APIコール
  • Class Component / Function Component の説明
  • 画面遷移

技術的に掘り下げたいところ

  • Expo / CLIの違い、メリットデメリット
  • Class Component / Function Componentの違い
    • どちらかというと Reactの内容

UI作成

    <View style={styles.container}>
      <View style={styles.itemContainer}>
        <View style={styles.leftContainer} />
        <View style={styles.rightContainer} />
      </View>
    </View>
  • <div>の代わりに<View>で区切る
const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
  itemContainer: {
    height: 100,
    width: '100%',
    borderColor: 'gray',
    borderWidth: 1,
    flexDirection: 'row',
  },
  leftContainer: {
    width: 100,
  },
  rightContainer: {
    flex: 1,
    padding: 10,
    justifyContent: 'space-between',
  },
  text: {
    fontSize: 16,
  },
  subText: {
    fontSize: 12,
    color: 'gray',
  },
});
  • flexDirection で向きを設定する
    • flexDirection: "column" でコンポーネントが縦に並ぶ
    • flexDirection: "row" で横に並ぶ
      • デフォルトは column
          <Text numberOfLines={3}>
            Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
            eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
            ad minim veniam, quis nostrud exercitation
          </Text>
          <Text>ReactNews</Text>
  • numberOfLines
    • 表示する行数を指定できる
    • 行数を超える場合は「...」で省略してくれる

styles関連

  • alignItems
    • flex-start 向きに対してスタート地点から始まる
    • flex-end 向きに対して終点に接地する
      • flexDirection で指定した向きによって配置が決まる
  • justifyContent
    • flexDirectionで指定した向きに対して縦方向に位置調整が出来る
    • space-between 均等な間を確保する
    • space-around コンポーネントの外側の余白も設ける

コンポーネント化

  • Reactとほぼ変わらない

APIコール

useState

  • Function ComponentのHooksを利用
    • state等のReactの機能をクラスを書かずに使えるようになる
    • ReactNative 0.59以降でサポート
      • React Expo SDK33以降で対応
const [cont,setCount] = useState(0);
  • count でstateの値を保持
  • setCount stateの値を更新するメソッド
  • 引数(0)はcountの初期値を表す
function Example() {
  // Declare a new state variable, which we'll call "count"
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

useEffect

  const subscription = props.source.subscribe();
  return () => {
    // Clean up the subscription
    subscription.unsubscribe();
  };
});
  • レンダーのタイミングで関数が実行される
useEffect(
  () => {
    const subscription = props.source.subscribe();
    return () => {
      subscription.unsubscribe();
    };
  },
  [props.source],
);
  • 条件付き副作用
    • 第2引数の値が変更したタイミングでuseEffectの中の関数を実行する(第1引数)
    • 2つ目の引数に空の配列を渡すとマウント時に実行され、アンマウント時にクリーンアップされる
    • 更新時(画面の再描画)には実行されないようになる

axios

axiosとは

  • REST API等を叩くときに使う

セットアップ

npm install axios
axiosをインストールしておく

import axios from 'axios';
axiosをインポート

  const fetchArticles = async () => {
    try {
      const response = await axios.get(URL);
      setArticles(response.data.articles);
    } catch (error) {
      console.error(error);
    }
  };

APIコールでニュース記事を取得

画面遷移

Reduxによるクリップ管理

Reduxとは

状態の集中管理

  • store
    • 状態を集中管理する場所
  • reducer
    • storeを更新する役目を担う
    • 前回のstateとActionを受け取って新しいstateをリターンする関数
  • action
    • type
      • Actionの種類を識別するための予め定義された文字列
    • payload
      • 実行する際に使われる任意のデータ

ActionがDispatch(送信)されると、Storeから渡されたOldStateとActionから渡されたPayloadを元に新たなNewStateを生成する

実装

必要なパッケージのインストール

npm install redux react-redux

Actionの追加

今回追加するAction

  • ADD_CLIP
    • クリップを追加する
  • DELETE_CLIP
    • クリップを削除する
手順
  • store/actionsフォルダを作成
  • store/actions内にuser.jsを追加
  • ADD_CLIPとDELETE_CLIPの追加
export const addClip = ({clip}) =>{
    return{
        type: 'ADD_CLIP',
        clip,
    };
};

export const deleteClip = ({clip}) =>{
    return{
        type: 'DELETE_CLIP',
        clip,
    };
};

Reducerの追加

  • store/reducersフォルダを作成
  • store.reducers内にuser.jsを追加
const initialState = {
  clips: [],
};

const reducer = (state = initialState, action) => {
  switch (action.type) {
    case "ADD_CLIP":
        return {
            ...state,
            clips:[...state.clips,action.clip]
        };
    case "DELETE_CLIP":
        return {
            ...state,
            clips:state.clips.filter(clip => clip.url !== action.clip.url),
        };
    default:
      return state;
  }
};

export default reducer;

Storeの追加

Storeは、巨大なjsonツリーのようなイメージ。

  • store
    • user
      • clipse[]
    • user
      • clips
    • ...
Storeの作成
  • store/index.jsの作成
    • ツリー構造を作るため、combineReducersのimport
    • 作成したuserReducerを配置する
    • ルートのReducerを定義する
      • createStoreのimportが必要
import { createStore, combineReducers } from "redux";
import userReducer from "./reducers/user";

const rootReducer = combineReducers({
  user: userReducer,
});

const store = createStore(rootReducer);

export default store;
  • アプリケーションでstoreを使うためにApp.jsでの呼び出し、定義
    • Providerとstoreのimport
    • AppNavigatorをProviderで囲む
import React from "react";
import AppNavigator from "./navigation/AppNavigator";
import { Provider } from "react-redux";
import store from "./store";

export default App = () => {
  return (
    <Provider store={store}>
      <AppNavigator />
    </Provider>
  );
};
つ

Expo と CLIの比較

簡単に調査してみる
https://www.it-swarm-ja.tech/ja/react-native/expo-cliとreact-native-cliの違いは何ですか?/809099320/

React Native CLI

メリット

  • Java/Objective-c で記述されたネイティブモジュールを追加できる

デメリット

  • Android Studio / Xcodeが必要
  • iOS開発にMacが必須
  • 実機デバッグにはUSB接続が必要
  • アプリ配布には.apk/.ipaファイルを全体に送信する必要がある
  • Push通知やAssetManager等、手動でインストールしてnpmとリンクさせる必要がある(?)
  • プロジェクト設定、デバイス構成等が複雑で手間がかかる

React Native Expo

メリット

  • 設定が簡単、数分で完了
  • アプリの配布が簡単。QRコードやリンクで開ける
  • アプリの実行にビルドが必要ない
  • 標準プロジェクトに基本的なライブラリが揃っている(Push通知、AssetManager等)
  • .apk/.ipaファイルを作成できる(ストア配布が簡単?)

デメリット

  • ネイティブモジュールの追加が出来ない
  • Java/Objective-Cのネイティブコードを使用するライブラリは使えない
  • ExpoKit? が色々デメリットを抱えている(要調査)

比較結果

Expoはお手軽だが、細かいネイティブ機能が扱いづらい。
セットアップやメンテが大変な分、最新のネイティブ機能を扱えるのがReact Native CLIから構築する場合となる。