【React Native入門】8-1 サンプルアプリの開発 Yahoo!ニュースチェッカー

「React Native入門　掌田 津耶乃著」にて動作確認したコードを逐一まとめた記事です。
基本は自分用のメモですので、動作確認したい場合ご利用ください。
ある程度は1記事を更新していき、セッションが切り替わったら別記事に残していこうと思います。

[ P.336〜P.348 ] Yahoo!ニュースのRSSを使おう

全然理解できていないしWebViewのところでエラーになるため
コードのみ載せておきます。

主なニュース画面までは正常通り動作しますが
各ニュースをタップするとエラーになります。
もし原因と対策がわかる方コメントお願いします。

```js:App.js
import React, { Component } from 'react';
import { StyleSheet,  ScrollView, WebView, StatusBar, Alert, TouchableOpacity, Text, View } from 'react-native';
import { Header } from 'react-native-elements';
import { createStackNavigator } from 'react-navigation';

window.DOMParser = require('xmldom').DOMParser;

// RSS名
const site_items = ['主なニュース','国際ニュース','国内ニュース','経済関係','スポーツ','IT関連','科学技術'];

// RSSアドレス
const site_links = [
  'https://news.yahoo.co.jp/pickup/rss.xml',
  'https://news.yahoo.co.jp/pickup/world/rss.xml',
  'https://news.yahoo.co.jp/pickup/domestic/rss.xml',
  'https://news.yahoo.co.jp/pickup/economy/rss.xml',
  'https://news.yahoo.co.jp/pickup/sports/rss.xml',
  'https://news.yahoo.co.jp/pickup/computer/rss.xml',
  'https://news.yahoo.co.jp/pickup/science/rss.xml'
];

let sel_index = 0; // 選択index
let access_url = ''; // 選択url

// サイトの一覧画面
class Home extends React.Component {
  static navigationOptions = {
    title: 'Yahoo News',
    headerStyle: { backgroundColor: '#4169e1', },
    headerTintColor: 'white',
  }
  constructor(props) {
    super(props);
  }
  getView = (item, i) => (
    <TouchableOpacity onPress={ () => this.goNews(i) }>
      <View style={ styles.site }>
        <Text
          style={{ fontSize:32 }}>
          { i+1 }. { item }
        </Text>
      </View>
    </TouchableOpacity>
  );
  goNews = (n) => {
    sel_index = n;
    this.props.navigation.navigate('Genre');
  }
  render() {
    return (
      <View style={ styles.base }>
        <View style={ styles.body }>
          <ScrollView>
            { site_items.map((item, i) => this.getView(item, i)) }
          </ScrollView>
        </View>
      </View>
    );
  }
}

// 選択したサイトのニュース一覧画面
class Genre extends React.Component {
  items = [];

  static navigationOptions = {
    title: site_items[sel_index],
    headerStyle: { backgroundColor: '#00aa00' },
    headerTintColor: 'white',
  }
  constructor(props) {
    super(props);
    this.state = {
      items: [{ title: 'wait...', link: '', pubDate: '' }],
    }

    let items = [];

    fetch(site_links[sel_index]).then((response) => {
      response.text().then((txt) => {
        const parser = new DOMParser();
        const xml = parser.parseFromString(txt);
        let maintitle = xml.getElementsByTagName('title')[0].childNodes[0].nodeValue;
        let elements = xml.getElementsByTagName('item');
        for(let i = 0;i < elements.length;i++) {
          let item = elements[i];
          let title = item.getElementsByTagName('title')[0].childNodes[0].nodeValue;
          let link = item.getElementsByTagName('link')[0].childNodes[0].nodeValue;
          let pubDate = item.getElementsByTagName('pubDate')[0].childNodes[0].nodeValue;
          items[i] = {
            title: title,
            link: link,
            pubDate: pubDate,
          }
        }
        this.setState({ items: items });
      });
    });
  }
  getView = (item, i) => (
    <TouchableOpacity onPress={ () => this.goContent(i) }>
      <View style={ styles.item }>
        <Text style={{ fontSize: 24 }}>{ item.title }</Text>
        <Text style={{ fontSize: 16 }}>{ item.pubDate }</Text>
      </View>
    </TouchableOpacity>
  );
  goContent = (n) => {
    access_url = this.state.items[n].link;
    this.props.navigation.navigate('Content');
  }
  render() {
    return (
      <View style={ styles.base }>
        <View style={ styles.body }>
          <ScrollView>
            { this.state.items.map((item, i) => this.getView(item, i)) }
          </ScrollView>
        </View>
      </View>
    );
  }
}

// 選択したニュースのWebページを表示する画面
class Content extends React.Component {
  static navigationOptions = {
    title: '選択コンテンツの内容',
    headerStyle: { backgroundColor: '#aa0000' },
    headerTintColor: 'white',
  }
  constructor(props) {
    super(props);
    this.state = { html: '' };
    fetch(access_url).then((response) => {
      response.text().then((txt) => {
        let re = /<a class="newsLink" href="([\w-?:./=]+)"/;
        let arr = txt.match(re);
        this.setState({ html: arr[1] });
      });
    });
  }
  render() {
    return(
      <View style={ styles.base }>
        <View style={ styles.body }>
          <WebView
            source={{ uri: this.state.html }}
            javaScriptEnabled={ true }
          />
        </View>
      </View>
    );
  }
}

// ナビゲーション
export default createStackNavigator(
  {
    Home: { screen: Home },
    Genre: { screen: Genre },
    Content: { screen: Content },
  },
  {
    initialRouteName: 'Home',
  }
);

const styles = StyleSheet.create ({
  base: {
    padding: 0,
    flex: 1,
    backgroundColor: '#ddd',
  },
  body: {
    padding: 10,
    flex: 1,
    backgroundColor: '#fff',
  },
  site: {
    margin: 5,
    padding: 10,
    backgroundColor: '#ddd',
  },
  item: {
    margin: 5,
    padding: 10,
    backgroundColor: '#dfd',
  },
});
```