備忘録

わかったことや わからなかったことや ひびのことを かくよ

React Native ではてなブックマークアプリをつくってみる 2

スワイプダウンして更新するやつを追加してみた

RefreshControl を使って、画面をスワイプダウンして ホッテントリ一覧を更新できるようにしてみた。

// components/BookmarkList.js

import React from 'react'
import { Text, View, FlatList, RefreshControl } from 'react-native'
import BookmarkListItem from './BookmarkListItem'

export default class BookmarkList extends React.Component {
  state = {
    refreshing: true,
    items: []
  }

  componentDidMount () {
    this._fetchFeed()
  }

  _fetchFeed = async () => {
    const feed = await this.props.fetchEntry()
    const items = feed.item
    console.dir(items)
    this.setState({
      refreshing: false,
      items
    })
  }

  _onRefresh = () => {
    this.setState({ refreshing: true })
    this._fetchFeed()
  }

  _keyExtractor = (item, index) => item.link

  _renderItem = ({ item }) => (
    <BookmarkListItem item={item} />
  )
  
  render () {
    return (
      <FlatList
        data={this.state.items}
        extraData={this.state.items}
        keyExtractor={this._keyExtractor}
        renderItem={this._renderItem}
        refreshControl={
          <RefreshControl
            refreshing={this.state.refreshing}
            onRefresh={this._onRefresh.bind(this)}
          />
        }
      />
    )
  }
}

こんな感じになりました。

f:id:ynakajima:20180106184557g:plain

リポジトリはこちら。

github.com

React Native ではてなブックマークアプリをつくってみる 1

最近、React Native のお勉強をしているので試しにはてなブックマークアプリをつくってみたい。

要件定義

僕ははてブを見る時にまずブコメからみる習慣があるので、下記のようなアプリにしたい。

  • ホッテントリの一覧がでる
  • 一覧のアイテムをタップするとまずブックマークコメントが表示される
    • メタブックマークがあればメタブ一覧を表示するボタンが出る
  • ブックマークされたページはブコメ一案にあるボタンを押すと閲覧できる
    • その際、魚拓があれば魚拓を閲覧することもできるようにしたい

そんな感じで作っていきます

まずはプロジェクトを初期化

Getting Started · React Native に載ってるとおりにプロジェクトを作成する。

アプリ名はとりあえず「HBCommentFirst」と名づけた。

$ yarn global add create-react-native-app
$ create-react-native-app HBCommentFirst
$ cd HBCommentFirst
$ yarn  start

コンソールにQRコードが表示されるので、スマホにインストールした Expoクライアントアプリ からQRを読み込むだけでアプリを実機で確認しながら開発できる。しかも、ブラウザでデバッグもできる。超便利。

ホットエントリーを読み込む

とりあえず、はてなブックマークホッテントリを読み込んでJSONにする関数を書いてみる。

ちなみに、Networking · React Native を参考にした。

// libs/HatenaBookmark.js

import X2JS from 'x2js'

const hotentry = 'http://b.hatena.ne.jp/hotentry.rss'

/**
 * ホットエントリーを読み込んでJSONを返す
 */
export const fetchHotEntry = () => {
  return fetchRss(hotentry)
}

/**
 * RSSをfetchしてJSONを返す
 */
const fetchRss = async (url) => {
  const response = await fetch(url)
  const rssText = await response.text()
  const x2js = new X2JS()
  const rss = x2js.xml2js(rssText)
  return rss.RDF
}
// App.js

import React from 'react'
import { StyleSheet, Text, View } from 'react-native'
import { fetchHotEntry } from './libs/HatenaBookmark'

export default class App extends React.Component {
  // ホットエントリーを読み込んで結果を出力
  async componentDidMount() {
    const feed = await fetchHotEntry()
    console.dir(feed)
  }

  render() {
    return (
      <View style={styles.container}>
        <Text>Hello!</Text>
      </View>
    )
  }
}

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

デバッガーにはこんな感じで出力される。

f:id:ynakajima:20180106015523p:plain

リストとして表示してみる

FlatList コンポーネントを利用して、読み込んだホッテントリのフィードをリストとして表示してみる。

// components/BookmarkListItem.js

import React from 'react'
import { StyleSheet, Text, View } from 'react-native'

export default class BookmarkListItem extends React.Component {
  render () {
    const item = this.props.item
    return (
      <View style={styles.item}> 
        <Text
          style={styles.itemTitle}
          numberOfLines={3}
          ellipsizeMode={'tail'}
        >
          { item.title }
        </Text>
        <Text
          style={styles.itemDesc}
          numberOfLines={2}
          ellipsizeMode={'tail'}
        >
          { item.description }
        </Text>
        <Text style={styles.itemCount}>{ item.bookmarkcount.toString() } users</Text>
      </View>
    )
  }
}

const styles = StyleSheet.create({
  item: {
    padding: 15,
    borderBottomColor: '#eee',
    borderBottomWidth: 1
  },
  itemTitle: {
    fontSize: 14,
    lineHeight: 14 * 1.6,
    fontWeight: 'bold'
  },
  itemDesc: {
    marginTop: 8,
    fontSize: 13,
    lineHeight: 13 * 1.6,
    color: '#666'
  },
  itemCount: {
    marginTop: 8,
    fontSize: 13,
    color: '#c00'
  }
})
// components/BookmarkList.js

import React from 'react'
import { Text, View, FlatList } from 'react-native'
import BookmarkListItem from './BookmarkListItem'

export default class BookmarkList extends React.Component {
  state = {
    items: []
  }

  async componentDidMount () {
    const feed = await this.props.fetchEntry()
    const items = feed.item
    console.dir(items)
    this.setState({ items })
  }

  _keyExtractor = (item, index) => item.link

  _renderItem = ({ item }) => (
    <BookmarkListItem item={item} />
  )
  
  render () {
    return (
      <FlatList
        data={this.state.items}
        extraData={this.state.items}
        keyExtractor={this._keyExtractor}
        renderItem={this._renderItem}
      />
    )
  }
}
// App.js

import React from 'react'
import BookmarkList from './components/BookmarkList'
import { View } from 'react-native'
import { fetchHotEntry } from './libs/HatenaBookmark'

export default class App extends React.Component {
  render() {
    return (
      <View style={{marginTop: 20}}>
        <BookmarkList fetchEntry={fetchHotEntry} />
      </View>
    )
  }
}

こんな感じになりました。

f:id:ynakajima:20180106030657p:plain

Text モジュールのnumberOfLinesellipsizeModeプロパティが非常に便利で感動した。

とりあえず今日は以上。

ちなみにソースコード一式は下記にあります。

github.com