React Nativeを触ってみる
はじめに
初めまして!プロダクト開発部のタンと申します。
最近、弊社の新サービスを開発するプロジェクトに携わってたことで、いろいろな新しい技術を学んだことができました。その中にReactというJavascriptライブラリーがありまして、javascriptも興味がありますので、それとReact Nativeというネイティブアプリを開発するためのライブラリーを調べて、触ってみました。React Nativeはとても素晴らしいライプラリーだと思いますので、今回ご紹介したいと思います!
React-Nativeとは
- ReactはFacebookが開発したUIのパーツを作るためのJavascriptライブラリです
- React NativeはReactベースでネイティブアプリを構築できるライブラリです
特徴
- Javascriptだけで両方IosとAndroidプラットフォームのアプリを構築できます
- WebのCSSの属性でUIを調整できます
- IosとAndroidの基本的なコンポーネントはサポートされいて、使うことができます
- 拡張性(例えば: React Nativeはまだサポートしてないコンポーネントを使いたい場合、自分で開発し、追加できます)
- chromeやSafariでデバッグすることができます
- オプンソースのライプラリなので、コミュニティが広い
デメリット
- いくつかのコンポーネントはまだサポートされていません。例えば: Map, AndroidのpushNotification
- WindowとLinuxでIosアプリをビルドできません
- 複雑なアプリを開発したい場合、React Nativeの以外にReduxやRelayなどを勉強するべきです
開発環境を設定する
Macで開発環境の設定する方法を紹介します。
MacでReact Nativeの開発環境を立ち上げるために、以下のツールをインストールする必要があります
- Xcode
- Nodejs
1 2 |
brew install node |
1 2 |
brew install watchman |
これはFacebookが作ったファイルの変更を監視するためのツールです。
- React Native CLI
1 2 |
npm install -g react-native-cli |
サンプルアプリを作ってみよう
簡単な画像スライドショーアプリを作ってみましょう!
新規プロジェクトを作る
まず、React Native CLIで簡単に新規のプロジェクトを作ってください
1 2 |
react-native init simpleSlide |
アプリを走ってみる
以下のコマンドを実行したら、iOS Simulatorにアプリがインストールされて、表示されます
1 2 3 4 |
cd firstProject react-native run-ios |
ソースコードを変更する
React NativeはJavascriptのES2015を使いますので、ES2015が知らない方は事前に調べてください。
プロジェクトの構造は以下の通りです。
- index.js: Reactアプリ(App.js)を登録して、初期化するところです。
1 2 3 4 |
import { AppRegistry } from 'react-native'; import App from './App'; AppRegistry.registerComponent('simpleSlide', () => App); |
- App.js: アプリのメインクラスです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
import React, {Component} from 'react'; import { Animated, StyleSheet, View } from 'react-native'; import Header from "./components/Header"; import Item from "./components/Item"; import {listImages} from "./data/images"; import {APP_WIDTH, APP_HEIGHT, APP_PADDING_TOP, ITEM_SIZE} from "./constants/app"; /** * アプリのメインクラフ */ export default class App extends Component { constructor(props) { super(props); this.state = { scrollX: new Animated.Value(0), listImages: null } } // データから画像リストを取得して、アプリのstateに格納する loadImages() { let currState = this.state; currState.listImages = listImages; this.setState(currState); } componentWillMount() { this.loadImages(); } render() { // スライド画像リストを作成する let listItems = Object.keys(this.state.listImages).map((key) => { let imageUrl = this.state.listImages[key].url; let description = this.state.listImages[key].description; return <Item key={key} id={key} imageUrl={imageUrl} description={description} scrollX={this.state.scrollX}/> }); return ( <View style={styles.container}> <Header/> <Animated.ScrollView style={styles.slide} contentContainerStyle={{ alignItems: 'flex-start', justifyContent: 'center', flexGrow: 1 }} horizontal={true} decelerationRate={0} snapToInterval={ITEM_SIZE} scrollEventThrottle={16} snapToAlignment="start" showsHorizontalScrollIndicator={false} onScroll={Animated.event( [{nativeEvent: {contentOffset: {x: this.state.scrollX}}}] )} > {listItems} </Animated.ScrollView> </View> ); } } const styles = StyleSheet.create({ container: { height: APP_HEIGHT, }, slide: { flex: 0.65, width: APP_WIDTH, marginTop: APP_PADDING_TOP }, }); |
- components: アプリで使うコンポーネント
- Header.js: アプリのヘッダー
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
import React, {Component} from 'react'; import { Text, Animated, View, StyleSheet, } from 'react-native'; import {BAR_HEIGHT} from '../constants/app' /** * アプリのヘッダ */ export default class Header extends Component { constructor(props) { super(props); } render() { return ( <Animated.View style={styles.header}> <View style={styles.bar}> <Text> Simple Photo Slide </Text> </View> </Animated.View> ); } } const styles = StyleSheet.create({ header: { position: 'absolute', top: 0, left: 0, right: 0, backgroundColor: '#03A9F4', overflow: 'hidden', }, bar: { marginTop: 25, height: BAR_HEIGHT, alignItems: 'center', justifyContent: 'center', } }); |
- Item.js: スライドショーのアイテム
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
import React, {Component} from 'react'; import { Image, Text, Animated, StyleSheet } from 'react-native'; import {ITEM_FONT, ITEM_PADDING, ITEM_SIZE} from "../constants/app"; /** * スライド画像アイテム */ export default class Item extends Component { constructor(props) { super(props) } render() { let imgSource = {uri: this.props.imageUrl}; let inputRange = [ (this.props.id - 2) * ITEM_SIZE, (this.props.id - 1) * ITEM_SIZE, this.props.id * ITEM_SIZE, (this.props.id + 1) * ITEM_SIZE ]; let scale = this.props.scrollX.interpolate({ inputRange: inputRange, outputRange: [0.7, 1, 0.7, 1], extrapolate: 'clamp' }); return ( <Animated.View style={[ { paddingLeft: ITEM_PADDING, paddingRight: ITEM_PADDING, alignItems: "center", backgroundColor: 'transparent', marginVertical: 10, transform: [ { scale: scale } ] } ]}> <Image source={imgSource} style={styles.image}/> <Text style={styles.description}> {this.props.description} </Text> </Animated.View> ); } } const styles = StyleSheet.create({ image: { width: ITEM_SIZE, height: ITEM_SIZE, borderRadius: ITEM_SIZE / 2 }, description: { fontFamily: ITEM_FONT, fontSize: 20, color: '#FF0088' } }); |
- app.js: いくつか属性を定義するところ。例えば: アプリの長さ、高さやスライドショーのアイテムアイテムのサイズなど
1 2 3 4 5 6 7 8 9 10 11 12 |
import {Dimensions } from 'react-native'; let { height, width } = Dimensions.get('window'); export const APP_WIDTH = width; export const APP_HEIGHT = height; export const BAR_HEIGHT = 32; export const APP_PADDING_TOP = BAR_HEIGHT * 3; export const ITEM_SIZE = width * 0.68; export const ITEM_PADDING = width * 0.03; export const ITEM_FONT = "Apple SD Gothic Neo"; |
- data:
- images.js: スライドショーの画像データを定数で定義するためです
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
export const listImages = [ { url: 'https://c1.staticflickr.com/9/8325/28515392361_ac78d010eb_b.jpg', description: 'Gal Gadot' }, { url: 'https://c1.staticflickr.com/3/2701/4252994964_3c961d5d0d_b.jpg', description: 'Scarlett Johansson' }, { url: 'https://timedotcom.files.wordpress.com/2015/01/jennifer-lawrence.jpg', description: 'Jennifer Lawrence' }, { url: 'https://d.ibtimes.co.uk/en/full/1422570/dakota-johnson.jpg', description: 'Dakota Johnson' }, ]; |
処理について、簡単に説明したいと思います。
- アプリケーションのレイアウトは以下の二つのコンポーネントで分けて、App.jsにインポートすることで使えます
– Header.js: アプリのヘッダーのコンポーネント
– Item.js: スライドショーのアイテムのコンポーネント - UIを変更するため、各のクラスにstyles定数を定義し、CSSと同じ属性で変更します
- アニメーションの処理はReact NativeのAnimatedを使います
デバッグ方法について
上記に書いてある通り、React Nativeはjavascriptを使いますので、webアプリケーションと同じブラウザーでデバッグすることができます
- iOS Simulatorでアプリを走っている時に、「⌘D」ショートカットキーで開発メニューを開いて、「Debug JS Remotely」を選択すると、MACのブラウザーのコンソールでデバッグすることができます
最後に
今回はReact Nativeについて紹介しました。
React Nativeを使って、javascriptだけで両方 IOS、Androidとも動くことができるアプリケーションを構築できますので、Webエンジニアにとって、とてもいいライブラリだと思います。
Webエンジニアの方はネイティブアプリケーションを開発したい場合、React Nativeをオススメします。ぜひ試してください!!!