「React NativeとExpoで作るiOS・Androidアプリ開発入門 3/3」の感想・備忘録

スポンサーリンク

点数

78

感想

React Native Elementsの使い方とサンプルアプリの作成、が書かれていた。

サンプルアプリの作成は、必要な機能を一つずつ追加していく流れで書かれていてわかりやすかった。

インストール

npm install @rneui/themed @rneui/base react-native-vector-icons
※ React Native0.60より古いバージョンではnpx react-native link react-native-vector-iconsも必要

インポート

import { Button, Card, Divider, Input, Icon, ListItem } from '@rneui/themed'

Button

<Button title="ボタン" icon={{name:"forward"}}/>

Divider

<Divider style={{marginVertical:10}}/>

Input

<Input placeholder='名前を入力してください' errorMessage='ここにエラ〜メッセージが入ります'/>

Icon

<Icon name="vibrate" type="material-community" color="#0f0"/>

Card

<Card>
<Card.Title>カード</Card.Title>
<Card.Divider />
<Text>ここに本文が入ります</Text>
</Card>

ListItem

<ListItem>
<Icon name="keyboard" color="grey" />
<ListItem.Content>
<ListItem.Title>タイトル</ListItem.Title>
<ListItem.Subtitle>サブタイトル</ListItem.Subtitle>
</ListItem.Content>
</ListItem>

サンプルアプリ(Qiita Reader)の作成

インストール

  • npx create-expo-app QiitaReader
  • npm install @rneui/themed @rneui/base react-native-vector-icons
  • npm install @react-navigation/native @react-navigation/native-stack @react-navigation/bottom-tabs
  • npx expo install react-native-screens react-native-safe-area-context
  • npm install @react-native-async-storage/async-storage
  • npx expo install react-native-webview

ソースコード(TagScreensのみ)

import { StyleSheet } from 'react-native'
import { NavigationContainer } from '@react-navigation/native'
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'
import { Icon } from '@rneui/themed'
import TagScreens from './TagScreens'
import KeywordScreens from './KeywordScreens'

const Tab = createBottomTabNavigator()
export default function App () {
  return (
    <NavigationContainer>
      <Tab.Navigator initialRouteName="Tag" screenOptions={() => ({
        tabBarIcon: () => <Icon name="list" type="material"/>,
      })
      }>
        <Tab.Screen name="Tag" component={TagScreens} options={{ title: "タグ", headerShown: false }}/>
        <Tab.Screen name="Keyword" component={KeywordScreens} options={{ title: "キーワード", headerShown: false }}/>
      </Tab.Navigator>
    </NavigationContainer>
  )
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
})
import { createNativeStackNavigator } from '@react-navigation/native-stack'
import TagList from './TagList'
import TagSubscriber from './TagSubscriber'
import TagPageList from './TagPageList'
import { Icon } from '@rneui/themed'
import WebViewPage from './WebViewPage'

const Stack = createNativeStackNavigator()
export default function TagScreens ({ navigation }) {
  return (
    <Stack.Navigator initialRouteName="TagList">
      <Stack.Screen name="TagList" component={TagList} options={{
        headerTitle: '登録済みのタグ', headerRight: () =>
          <Icon name="plus" type="material-community" onPress={() => navigation.navigate(
            'TagSubscriber')}/>,
      }}/>
      <Stack.Screen name="TagSubscriber" component={TagSubscriber} options={{ title: '新しいタグを登録', headerBackTitle: '戻る', headerBackTitleVisible: true }}/>
      <Stack.Screen name="TagPageList" component={TagPageList}  options={({ route }) => ({ title: `${route.params.tag}の記事一覧`})}/>
      <Stack.Screen name="WebViewPage" component={WebViewPage} options={({ route }) => ({ title: route.params.url })}/>
    </Stack.Navigator>
  )
}
import { FlatList, RefreshControl, View } from 'react-native'
import { useEffect, useState } from 'react'
import AsyncStorage from '@react-native-async-storage/async-storage'
import { Button, ListItem } from '@rneui/themed'

export default function TagList ({ navigation }) {
  const [tags, setTags] = useState([])
  const [refreshing, setRefreshing] = useState(false)
  useEffect(() => {
    loadTags()
    const unsubscribe = navigation.addListener('focus', () => {
      loadTags()
    });
    return unsubscribe;
  }, [])
  const loadTags = async() => {
    setRefreshing(true)
    let tags = await AsyncStorage.getItem('tags')
    if (tags === null) {
      tags = '[]'
    }
    setTags(JSON.parse(tags))
    setRefreshing(false)
  }
  return (
    <>
      <FlatList data={tags} keyExtractor={item => item.id} renderItem={({ item }) => (
        <ListItem onPress={() => navigation.navigate('TagPageList',
          { tag: item.id })}>
          <ListItem.Content>
            <ListItem.Title>{item.id}</ListItem.Title>
          </ListItem.Content>
        </ListItem>
      )} refreshControl={
        <RefreshControl refreshing={refreshing} onRefresh={loadTags}/>}/>
      <View style={{ alignItems: "center" }}>
        <Button title="全削除" containerStyle={{ width: 100, marginBottom: 10 }} onPress={async () => {
          await AsyncStorage.removeItem('tags');
          alert('削除しました')
        }}/>
      </View>
    </>
  )
}
import { useEffect, useState } from 'react'
import { FlatList } from 'react-native'
import { ListItem } from '@rneui/themed'
import AsyncStorage from '@react-native-async-storage/async-storage'

export default function TagSubscriber() {
  const [tags, setTags] = useState([])
  useEffect(() => {
    fetchTags()
  }, [])
  const fetchTags = async()=> {
    const res = await fetch("https://qiita.com/api/v2/tags?page=1")
    const tags = await res.json()
    setTags(tags)
  }
  const updateTags = async tag => {
    let tags = await AsyncStorage.getItem('tags');
    if (tags === null) {
      tags = "[]";
    }
    const json = JSON.parse(tags).concat(tag)
    await AsyncStorage.setItem('tags', JSON.stringify(json));
    alert('タグを追加しました')
  }
  return (
      <FlatList data={tags} renderItem={({item}) => (
        <ListItem onPress={async ()=> await updateTags(item)}>
          <ListItem.Content>
            <ListItem.Title>{item.id}</ListItem.Title>
          </ListItem.Content>
        </ListItem>
      )}/>
  );
}
import { FlatList } from 'react-native'
import React, { useEffect, useState } from 'react'
import { ListItem } from '@rneui/themed'

export default function TagPageList ({ navigation, route }) {
  const [articles, setArticles] = useState([])
  const [isLoaded, setIsLoaded] = useState(false)
  useEffect(() => {
    loadArticles()
  }, [])
  const loadArticles = async() => {
    const res = await fetch(
      `https://qiita.com/api/v2/items?page=1&per_page=10&query=tag:${route.params.tag}`)
    const articles = await res.json()
    setArticles(articles)
    setIsLoaded(true)
  }
  return (
    <>
      {(isLoaded && articles.length === 0) ? (
        <ListItem>
          <ListItem.Content>
            <ListItem.Title>0件</ListItem.Title>
          </ListItem.Content>
        </ListItem>
      ) : (
        <FlatList data={articles} renderItem={({ item }) => (
          <ListItem onPress={() => navigation.navigate('WebViewPage',
            { url: item.url })}>
            <ListItem.Content>
              <ListItem.Title>{item.title}</ListItem.Title>
              {item.user.name !== '' && <ListItem.Subtitle>{item.user.name}</ListItem.Subtitle>}
            </ListItem.Content>
          </ListItem>
        )}/>
      )}
    </>
  )
}
import WebView from 'react-native-webview'

export default function WebViewPage ({ navigation,route }) {
  return <WebView source={{ uri: route.params.url }} style={{ flex: 1 }} />;
}

コメント