ローディング中

react-nativeで一人前のiOSアプリ開発者を目指す 第3回 本のリストを取得するアプリ

こんにちは、個別指導塾コミット塾長、AWESOME開発担当の船津です。
引き続きLearning React Nativeを使って勉強していきます。

amazon

今回は前回の内容を踏まえつつ、ListViewを使ったアプリを作っていきます。
NewYork TimesのAPIを利用して、ジャンルごとに本の一覧を取得するアプリになります。
APIkeyはhttps://developer.nytimes.com/から取得して下さい メールアドレスだけで取得出来ます。

 

やりたいことは…

  • 初期状態でも何らかの本の一覧が表示されている(今回はe-book-fictionの一覧)
  • 入力欄に入力するとほんの一覧が更新される
  • 存在しないカテゴリを選択すると、エラーページが表示される

 

用意するのは以下のファイルです。

index.ios.js アプリの登録用
BookList.js アプリの本体、ListViewを書きます
BookItem.js ListViewの中身を書きます

まずはreact-native init BookListをして新しいアプリの雛形を作ります。

早速 index.ios.js を見てみましょう

import React, { Component } from 'react';
import {
  AppRegistry
} from 'react-native';

var BookList = require('./BookList')
AppRegistry.registerComponent('BookList', () => BookList);

次にBookList.js

'use strict'

import React, { Component } from 'react';
import {
  StyleSheet,
  Text,
  View,
  Image,
  ListView,
  TextInput,

} from 'react-native';

var BookItem = require('./BookItem');
var API_KEY = 'hogehogehoge';
var API_STEM = 'https://api.nytimes.com/svc/books/v3/lists'

class BookList extends Component {
  constructor() {
    super();
    // データソースを定義し、初期値を与えます
    var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2 });
    this.state = {
      query: 'e-book-fiction',
      dataSource: ds.cloneWithRows([]),
      error: false
    };
    // onChangeアクションに対してthisをbindします。
    this.onChange = this.onChange.bind(this);
  }
  onChange(event){
    var query = event.nativeEvent.text;
    this.setState({
      query: query
    });
    this._refreshData(this.state.query);
  }
	//デバイスの立ち上がり時にのみ実行される関数です。初期クエリの'e-book-fiction'でデータを取得します。
  componentDidMount() {
    this._refreshData(this.state.query);
  }
	// APIでデータを取得する cloneWithRowsで配列を読み込ませます。
  _refreshData(query) {
    var endpoint = <code>MARKDOWN_HASH84f1883cbf8d62980fdf7a2691c1b5cbMARKDOWN_HASH</code>
    fetch(endpoint)
      .then((response) =&gt; response.json())
      .then((rjson) =&gt; {
        console.log(rjson);
        this.setState({
          dataSource: this.state.dataSource.cloneWithRows(rjson.results.books),
          error: false
        });
      })
      .catch((error) =&gt; {
        console.warn(error);
        this.setState({
          error: true
        });
      });
  }

	//エラー時に表示するページ
  _renderError() {
    return (
      &lt;View style={styles.container}&gt;
        &lt;View style={styles.queryContainer}&gt;
          &lt;Text&gt;
            No result for {this.state.query} Please input again
          &lt;/Text&gt;
          &lt;TextInput placeholder=&quot;Please input query&quot; style={[styles.query, styles.mainText]} returnKeyType=&quot;go&quot; // 入力が完了して、「go」ボタンを押した際に呼び出される関数を定義します。 onSubmitEditing={this.onChange}/&gt;
        &lt;/View&gt;
      &lt;/View&gt;
    );
  }
	//BookItem.jsでモジュール化したListViewを読み込みます
  _renderRow(rowData) {
      return &lt;BookItem coverURL={rowData.book_image} title={rowData.title} author={rowData.author}/&gt;;
  }
	// ヘッダー
  _renderHeader() {
    return (
      &lt;View style={styles.sectionDivider}&gt;
        &lt;Text style={styles.headingText}&gt;
          Best Seller List
        &lt;/Text&gt;
      &lt;/View&gt;
    );
  }
	// フッター
  _renderFooter() {
    return (
      &lt;View style={styles.sectionDivider}&gt;
        &lt;Text&gt;
          Data from New York Times Best sellers list.
        &lt;/Text&gt;
      &lt;/View&gt;
    );
  }
  
   // Viewを描画します
  render() {
    if(this.state.error){
      return this._renderError();
    }
    else {
      return (
        &lt;View style={styles.container}&gt;
          &lt;View style={styles.queryContainer}&gt;
            &lt;TextInput placeholder=&quot;Please input query&quot; style={[styles.query, styles.mainText]} returnKeyType=&quot;go&quot; onSubmitEditing={this.onChange}/&gt;
            &lt;Text style={styles.headingText}&gt;
              Search results for {this.state.query}
            &lt;/Text&gt;
          &lt;/View&gt;
          // リストビューのパラメータを設定します。enableEmptySectionsはそのうち指定しなくてもよくなるかも
          
          &lt;ListView enableEmptySections={true} dataSource={this.state.dataSource} renderRow={this._renderRow} renderHeader={this._renderHeader} renderFooter={this._renderFooter} /&gt;
        &lt;/View&gt;
      );
    }
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
    paddingTop: 24,
  },
  list: {
    flex: 1,
    flexDirection: 'row',
  },
  listContent: {
    flex: 1 ,
    flexDirection: 'column',
  },
  row: {
    flex: 1,
    fontSize: 24,
    padding: 42 ,
    borderWidth: 1,
    borderColor: '#dddddd',
  },
  sectionDivider: {
    padding: 8,
    backgroundColor: '#eeeeee',
    alignItems: 'center'
  },
  headingText: {
    flex: 1,
    fontSize: 24,
    alignSelf: 'center',
  },
  button: {
    flex: 1,
    padding: 10,
    borderColor: '#000',
    borderRadius: 4,
    borderWidth: 2,
    alignSelf: 'flex-end',
    textAlign: 'center',
  },
  mainText: {
    fontSize: 16,
    color: '#000',
    alignItems: 'center',
  },
  query: {
    alignSelf: 'center',
    marginTop: 30,
    width: 300 ,
    height: 30,
    borderWidth: 1,
    borderColor: '#000',
    borderRadius: 4,
    marginBottom: 20,
    padding:5,
  },
});

module.exports = BookList;

続いてBookItem.jsです

'use strict'

import React, { Component } from 'react';
import {
  StyleSheet,
  Text,
  View,
  Image,
  ListView,
} from 'react-native';


class BookItem extends Component {
	//入力値のvalidationを行います。ここではstringでないと入力出来ないようになっています。
  propTypes: {
    coverURL: React.propTypes.string.isRequired,
    author: React.propTypes.string.isRequired,
    title: React.propTypes.string.isRequired,
  }

  render() {
    return (
      <View style={styles.bookItem}>
        <Image style={styles.cover} source={{uri: this.props.coverURL}}/>
          <View style={styles.info}>
            <Text style={styles.author}>{this.props.author}</Text>
            <Text style={styles.title}>{this.props.title}</Text>
          </View>
      </View>
    )
  }
}

var styles = StyleSheet.create({
  bookItem: {
    flex: 1,
    flexDirection: 'row',
    backgroundColor: '#FFFFFF',
    borderBottomColor: '#AAAAAA',
    borderBottomWidth: 2,
    padding: 5
  },
  cover: {
    flex: 1,
    height: 150,
    resizeMode: 'contain'
  },
  info: {
    flex: 3,
    alignItems: 'flex-end',
    flexDirection: 'column',
    alignSelf: 'center',
    padding: 20
  },
  author: {
    fontSize: 18
  },
  title: {
    fontSize: 18,
    fontWeight: 'bold'
  }
});

//他のファイルから読み込めるようにexportします。
module.exports = BookItem;

完成するとこんな感じで表示されます。

 

スクリーンショット 2016-07-01 15.54.05

 

一応期待通りの動作をするようになりましたが、カテゴリの判定が厳しいので、入力欄ではなく、セレクトボックスにするといった工夫をしても良かったかもしれません。

ホームページ・デザイン制作のご相談・ご依頼は

079-451-5881

68ED4C65-BA1E-46D0-A7AC-B9869923C696 Created with sketchtool. A07C553F-CF16-4B7D-94FE-D36AE0A6297D Created with sketchtool. 37B7D8F4-7A18-4725-9EC6-595ABDF69D64 Created with sketchtool. 95DFB680-1EDF-4199-BC4A-BB6752EBA23C Created with sketchtool. 02DDF754-E1DB-4EF2-B6BB-C884722938C4 Created with sketchtool. NEW! 1A95E369-6469-4C46-B38F-F83410B928B0 Created with sketchtool. Group 5Group 2Group 4Group 3E4FC8CF2-721D-4699-8162-18E886C432C1 Created with sketchtool.