React NativeでQiitaクライアントアプリを作りたい人生だった

# はじめに
新卒エンジニア2ヶ月目。
Webやネイティブに関する知識は全く無かったのでいろんなものを参考に自分でも作ってみる。

Qiitaのクライアントアプリ作れたら面白そうだなと思ったので調べたら似たような(というかほぼやりたいこと）記事<https://qiita.com/y_matsuwitter/items/a7fc88e566b80b4c1eea>があった。ES5以前に書かれているようだったので自分なりにES6バージョンにしてみた。

# コードについて
GitHubにも上げてある<https://github.com/Ikeponias/qiita-client>。

## RootNavigator.js
``` navigator/RootNavigator.js
import React, { Component } from 'react';
import { 
    NavigatorIOS,
    StyleSheet,
} from 'react-native';

import QiitaItemsListContainer from '../containers/QiitaItemsListContainer';

export default class RootNavigator extends Component {
    render() {
        return (
            <NavigatorIOS
                style={ styles.navigator }
                initialRoute={{
                    component: QiitaItemsListContainer,
                    title: 'ReactQiita',
                }}
            />
        );
    }
}

// 各種デザイン要素
var styles = StyleSheet.create({
    navigator: {
      flex: 1
    },
});
```
React Native Navigationを使っていたが、たまにはNavigatorIOSを使ってみた（参考にしたサイトにもあったので）。直接`App.js`から送っても動くが、初期の画面にもNavigatorを使うと遷移に一貫性が生まれて良い。

## QiitaItemsListContainer.js
``` container/QiitaItemsListContainer.js
import React, { Component } from 'react';
import {
  Text,
  View,
  StyleSheet,
} from 'react-native';

import QiitaItemsListComponent from '../components/QiitaItemsListComponent';

const QIITA_URL
  = "https://qiita.com/api/v2/tags/reactnative/items?page=1&per_page=8";

export default class QiitaItemsListContainer extends Component {
  constructor(props) {
    super(props);

    this.state = {
      items: null,
      loaded: false,
    }
  }

  componentDidMount() {
    this.fetchData();
  }

  renderLoadingView() {
    return (
      <Text>
        Loading Movies...
      </Text>
    );
  }

  fetchData() {
    fetch(QIITA_URL)
      .then((response) => response.json())
      .then((responseData) => {
        this.setState({
          items: responseData,
          loaded: true,
        });
      })
      .catch((error) => console.log(error));
  }

  render() {
    return (
      this.state.loaded ?
        <QiitaItemsListComponent
          data={this.state.items}
          navigator={this.props.navigator}
        /> :
        this.renderLoadingView()
    );
  }
}
```
fetchしたデータをFlatListを持つコンポーネントに投げるだけのお仕事をするやつ。fetch終了時にloadedフラグを立てることでデータのロード終了を表現する。叩くAPIのURLのクエリに`page=1&per_page=8`と書いてあるのは、読み込みすぎてリクエスト制限かけられないようにするため(ホットリロードしてたら制限2回かけられた）なので好きに変えて良い。

## QiitaItemsListComponent.js
``` component/QiitaItemsListComponent.js
import React, { Component } from 'react';
import {
  StyleSheet,
  FlatList,
} from 'react-native';

import QiitaItemComponent from './QiitaItemComponent';

export default class QiitaItemsListComponent extends Component {
  constructor(props) {
    super(props);
  }

  _keyExtractor = (item, index) => item.id;
  render() {
    const { data, navigator } = this.props;
    return (
      <FlatList
        data={data}
        extraData={data}
        keyExtractor={this._keyExtractor}
        renderItem={({ item }) =>
          <QiitaItemComponent item={item} navigator={navigator} />}
        style={styles.flatList}
      />
    );
  }
}

// 各種デザイン要素
var styles = StyleSheet.create({
  flatList: {
    backgroundColor: '#FFFFFF',
    paddingTop: 44,
  },
});
```
FlatListを表現するやつ。Navigatorをpropsで送ってもらわないとこの後のWebViewで泣く（泣いた）。

## QiitaItemComponent.js
``` component/QiitaItemComponent.js
import React, { Component } from 'react';
import {
  Text,
  View,
  Image,
  StyleSheet,
  TouchableWithoutFeedback,
} from 'react-native';

import QiitaItemViewComponent from './QiitaItemViewComponent';

export default class QiitaItemComponent extends Component {
  constructor(props) {
    super(props);
  }

  onPressed() {
    const { item, navigator } = this.props;
    navigator.push({
      title: item.title,
      component: QiitaItemViewComponent,
      passProps: { url: item.url },
    });
  }

  render() {
    const { item } = this.props;
    return (
      <TouchableWithoutFeedback onPress={() => this.onPressed(item)}>
        <View style={styles.item}>
          <Image
            source={{ uri: item.user.profile_image_url }}
            style={styles.thumbnail} />
          <View style={styles.rightContainer}>
            <Text style={styles.title}>{item.title}</Text>
            <Text style={styles.name}>{item.user.id}</Text>
          </View>
        </View>
      </TouchableWithoutFeedback>
    );
  }
}

// 各種デザイン要素
var styles = StyleSheet.create({
  item: {
    borderWidth: 0.5,
  },
  rightContainer: {
    flex: 1,
  },
  title: {
    fontSize: 15,
    margin: 8,
    textAlign: 'left',
  },
  name: {
    fontSize: 12,
    margin: 8,
    textAlign: 'left',
  },
  thumbnail: {
    width: 80,
    height: 80,
    margin: 2,
  },
});
```
FlatList内のItemを表現するやつ。デザインは全く考えていないので今度ちゃんと勉強したい。各記事がタップされたらWebViewが開くようになっている。

## QiitaItemViewComponent.js
``` component/QiitaItemViewComponent.js
import React, { Component } from 'react';
import {
  WebView,
} from 'react-native';

export default class QiitaItemViewComponent extends Component {
  render() {
    return (
      <WebView
        source={{ uri: this.props.url }}
      />
    );
  }
}
```
WebViewでQiitaの記事を見るやつ。WebViewにもStyleを指定できるようなのでいじってみたい。

## App.js
``` App.js
import React from 'react';
import { 
  StyleSheet, 
  View, 
} from 'react-native';

import RootNavigator from './navigators/RootNavigator';

export default class App extends React.Component {
  render() {
    return (
      <View style={styles.container}>
        <RootNavigator />
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    justifyContent: 'center',
    paddingTop: 33,
  },
});

```
いつもの。

# まとめ
React Nativeに関する記事を取ってみた。APIのURLを変更すれば好きなものを取れる（当然ユーザ側から指定できるようにしたい）。
結果は↓
![スクリーンショット 2018-05-27 14.25.44.png](https://qiita-image-store.s3.amazonaws.com/0/212284/d6a87038-3757-c4b7-d1f1-c75decca4690.png)

少し手を加えればTwitterとかもできそう。Postもできるようになりたい。