React Native ハンズオン〜第2回

8 min read読了の目安(約7800字

この資料は React Native Japan主催の新生活応援!React Nativeハンズオン 入門編 #2 の資料です。

主に以下のような内容を扱います。

  • React基礎ざっくり(コンポーネント作成, props, stateの利用)
  • API通信によるデータ取得
  • React Navigationによる画面遷移

最終的にはこのようなニュース閲覧アプリを作成します。

Image from Gyazo

(Udemyコース React Native入門:ニュースアプリを作りながら覚えよう の一部抜粋になります)

0.環境構築

ハンズオン第1回の事前準備編をご参照ください!

https://zenn.dev/yutama_kotaro/articles/43c676adf2c7b6

Exopo CLI

npm install expo-cli --global
もしくは
yarn global add expo-cli

プロジェクトの作成

expo init hands-on-0418
cd hands-on-0418
yarn start

今回はblankを選択
スクリーンショット 2019-09-22 6.53.29.png

💡
TypeScriptで書きたい人は blank(TypeScript)を選んでも大丈夫です。
tabsを選ぶと画面下に3つのタブが付いたテンプレートを作成してくれます。

Managed Workflowはネイティブ側のコードが触れない代わりに、ネイティブの面倒な作業をExpoが全部肩代わりしてくれる楽なモードです。一方Bare Workflowはネイティブのコードも触れる柔軟性がある代わりに、ビルド作業などはネイティブの知識も必要になります。

シミュレーターを起動

simulator

もしくは

# expoサーバー起動&iOSシミュレーター起動
yarn ios

1.ニュースの項目を表示するコンポーネントを作る

1.1 レイアウトを考える

まずはUIを作りながら、ReactNativeのスタイリングに慣れてみましょう。

今回は3つの部分に分けて構成します。

itemContainer: 外枠。横並び。
leftContainer: 左の枠。幅100で固定。
rightContaier: 右の枠。縦並び。flex:1で可能な限り埋める。

      <View style={styles.itemContainer}>
        <View style={styles.leftContainer}>
          {/* 画像 */}
        </View>
        <View style={styles.rightContainer}>
          <Text style={styles.title} numberOfLines={3}>
            {/* テキスト 上段 */}
          </Text>
          <Text style={styles.subTitle}>
	   {/* テキスト 下段 */}
	  </Text>
        </View>
      </View>
項目 説明
flexDirection 縦並び(column)か横並び(row)か。デフォルトは縦
alignItems 並びと垂直方向の配置
justifyContent 並び方向の配置

https://github.com/takahi5/hands-on-news/commit/ca92d4463879a653daca7379093fff517b75f17a

1.2 ListItemコンポーネントに切り出す

再利用しやすいように別ファイルのcomponentに切り出しましょう。
componentsというフォルダを作って、ListItemというcomponentを作成します。

中身は一旦まるっとコピーましょう。

https://github.com/takahi5/hands-on-news/commit/ca92d4463879a653daca7379093fff517b75f17a

1.3 propsで情報を渡すように改修

このままではListItemの内容が常に同じなので、再利用できません。

なのでListItemの中身を親から指定できるようにしましょう。そのためにpropsを使います。

あとでstateというものも出てきますが、propsとstateが若干混同しやすいので整理しておきましょう。

propsはコンポーネントの性質を表し、親から与えられる不変な値です。
stateはコンポーネントの状態を表し、その時々で変更できる可変な値です。

ここではListItemに親からpropsとして渡しましょう。

まず引数でpropsを受け取るようにします。

export const ListItem = (props) => {
  const { title, subTitle, imageUrl } = props;

or
こう書いてもOK(こちらの方がよくあるパターン)

export const ListItem = ({ title, subTitle, imageUrl }) => {

ハードコーディングしていた部分をprops.imageUriのような形で受け取ったpropsを使って表示するように。

<Image style={{ width: 100, height: 100 }} source={{ uri: imageUrl }} />

親の方でpropsを渡すように。

      <ListItem
        imageUrl="https://picsum.photos/200"
        title="React Native は、Facebookが開発したクロスプラットフォームアプリ開発用フレームワークです。 ReactNative でアプリを作ることで、クロスプラットフォーム( iOS / Androidどちらでも動く)アプリを作ることができます。"
        subTitle="Techニュース"
      />

https://github.com/takahi5/hands-on-news/commit/c1ea706c7ffe08f24afc8e9fd7099559c0e199b0

2. APIから記事一覧を取得して表示する

2.1 FlatListで一覧表示する

まず一覧表示の仕組みを作ります。
表示する記事はとりあえずダミーのデータARTICLESを定義しておきます。

FlatListはスクロールする一覧画面などを作成するときに使用します。
ScrollViewというコンポーネントあるけど、FlatListのほうが動作が高速です。
一覧の項目数が多くなる場合はFlatListを使用しましょう。

FlatListのpropsについて

props 説明
data 表示するアイテムの配列
renderItem アイテムをレンダーする関数
keyExtractor 各アイテムにユニークなkeyを設定する関数

https://github.com/takahi5/hands-on-news/commit/618713bacc2c80a5e03dd19ba509783231982d4e
  • iPhoneXの対応のためSafeAreaViewを導入しましょう。上下の余白部分を避けてくれます。

2.2 下準備~ useState, useEffectを使う

先程の例では、記事データをconstで定義していましたが、APIから取得する場合は、取得したデータを変数に格納する必要があります。

この変数は可変な値なのでstateに格納する必要があります。
そこでuseStateというhooksを使います。
useStateを使うと関数コンポーネントにstateを持たせることができます。

また、度のタイミングでAPIを呼ぶかですが、今回はコンポーネントのマウント時にAPIを呼び出したいと思います。
その際に利用するのがuseEffectになります。
(APIを呼び出すような操作を副作用と呼びます)

https://github.com/takahi5/hands-on-news/commit/7fd36bf97d0b9ccd766ca69ab1e1a090e58986e6

2.3 APIから記事のデータを取得する

今回のハンズオン用に以下のようなAPIを用意しました。
ブラウザにこのURLを入れるとレスポンスのJSONが確認できます。

[GET] https://asia-northeast1-news-app-udemy.cloudfunctions.net/dummy_news

APIの呼び出しには axiosというライブラリを利用します。

以下コマンドをターミナルに入力してインストールしてください。

yarn add axios

コードの変更は以下になります。

https://github.com/takahi5/hands-on-news/commit/f54c2ed6e5ed8fd586cf44ee6697dcbed4e1d456

4. ReactNavigationで画面遷移

ルーティングのライブラリは色々あるけど、ExpoではReactNavigationを推奨します。

https://reactnavigation.org/

4.1 ライブラリのインストール

react-navigationのインストール

yarn add @react-navigation/native

Expo managed projectの場合

expo install react-native-gesture-handler react-native-reanimated react-native-screens react-native-safe-area-context @react-native-community/masked-view

今回はstack navigationという機能を使うため以下をインストール。

https://reactnavigation.org/docs/stack-navigator/
yarn add @react-navigation/stack

4.2 今までの画面をHomeScreenに分ける

今まで表示していた画面をHomeScreenという画面として定義して、React Navigationを用いて表示するようにします。
見た目としては今までと変わりません。

https://github.com/takahi5/hands-on-news/commit/b189e5c3f63ed23d9f8de0afc587dd61fb6acd06

参考: https://reactnavigation.org/docs/hello-react-navigation#creating-a-stack-navigator

4.3 DetailScreenを用意し、記事をタップしたら遷移するように

新しくDetailScreenを用意します。
また記事をタップしたら、そのDetailScreenに遷移するようにします。

navigatorにDetailScreenを追加する必要があります。

    <NavigationContainer>
      <Stack.Navigator>
        <Stack.Screen name="Home" component={HomeScreen} />
+       <Stack.Screen name="Detail" component={DetailScreen} />
      </Stack.Navigator>
      <StatusBar style="auto" />
    </NavigationContainer>

遷移はnavigation.navigate()で実行できます。

          <ListItem
            imageUrl={item.urlToImage}
            title={item.title}
            subTitle={item.author}
+           onPress={() => navigation.navigate('Detail')}
          />

💡
タップ検出にはPressableコンポーネントも使用できます。React Native 0.63から導入され、より細かな制御が可能になっています。

https://github.com/takahi5/hands-on-news/commit/e4bf25d138cf1a7bb29c100ad03e34ffb81710ed

参考:https://reactnavigation.org/docs/navigating

4.4 遷移時にパラメータを渡す

遷移元では、navigate()の第2引数に渡したいパラメータを指定できます。

onPress={() => navigation.navigate('Detail', { article: item })}

遷移先のスクリーンではprops.route.paramsで取得できます。

export default function HomeScreen(props) {
  const article = props.route.params.article;

https://github.com/takahi5/hands-on-news/commit/8b25bc42ed7f41ea81fbe02b74ebb2d69a417a28

参考:https://reactnavigation.org/docs/params

5. ステップアップ

時間に余裕がある方はチャレンジしてみてください!

5.1 リアルなニュースをAPIで取得する

今回はダミーのニュース取得APIを利用しましたが、リアルなニュースを取得できる無料のAPIがあります。

News API

https://newsapi.org/

このNews APIのレスポンスのJSON形式は、今回使用したダミーのAPIと同じなので、スムーズに移行できると思います。

5.2 WebViewでニュースを表示

上記のNews APIを使用すると、記事のURLを取得できます。
DetailScreenでWebViewを用いて、記事のウェブサイトを表示すると、だいぶニュースアプリっぽくなります。

WebView: https://docs.expo.io/versions/latest/sdk/webview/

5.3 ページング

今回はAPIを一度だけ叩いて、1ページ目だけを表示していますが、スクロールに応じて2ページ目以降を表示できるようにしてみましょう。

NewsAPIはpage=2のようなクエリパラメータを渡すと2ページ目以降も取得できます。

https://newsapi.org/docs/endpoints/everything

またFlatListにはスクロール最下部に達したときにonEndReachedというイベントを発火してくれます。

https://docs.expo.io/versions/latest/react-native/flatlist/#onendreached

この辺りを使ってページングを実装してみましょう。

おまけ

今回の内容のベースになっているUdemyコースの方では、さらに reduxの状態管理や、ストア公開についても解説しています。
興味のある方はぜひご覧になって下さい。