税理士目指す人のブログ

筋トレや読書のことをはじめとして、プログラミングその他日常生活における様々なことについて書いていきます。

Output Blog

主に筋トレ・プログラミングについて書きます

React Native入門⑦ 画面を引っ張って更新できるようにする【2020】

スポンサーリンク

React Native入門⑦ 画面を引っ張って更新できるようにする【2020】

React Nativeについて知りたいですか?
前回の記事では、WebViewを使ったニュースページの作り方を紹介しました。
本記事では、

  • RefreshControlの使い方
  • Twitterなどのように画面を引っ張ることでニュース内容を更新できる機能を追加

といったことを解説します。
アプリ開発に興味のある方必見です。
是非ご覧ください。

RefreshControlの使い方

RefreshControlコンポーネントはTwitterなどのように、画面を引っ張ると更新する機能です。
ニュースなどはそこそこの頻度で更新されますので、新しいニュースなどを読み込ませたいときにこのコンポーネントを利用します。

公式ドキュメントはこちらです。
RefreshControl · React Native

使い方は
scrollviewコンポーネントのrefreshcontrol属性に、返り値としてRefreshControlコンポーネントを指定すればよいです。
実際の使い方は後程記すコードを見ていただくとわかりやすいと思います。

サンプル

このコンポーネントは、Web版では使用できないので注意してください。

更新機能追加

前回に引き続き、ニュースアプリに機能を追加していきましょう。
ソースコードはこちら。

import * as React from 'react';
import {
  FlatList,
  View,
  ScrollView,
  Text,
  ActivityIndicator,
  RefreshControl
} from 'react-native';
import { WebView } from 'react-native-webview';
import { ListItem, Avatar, Icon } from 'react-native-elements';
import { NavigationContainer} from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';

function NewsList({route,navigation}) {
  const [data, setData] = React.useState([]);
  const [load, isLoaded] = React.useState(false);
  const [refresh,setRefresh] = React.useState(false)

  function getNews() {
    var url =
      'https://newsapi.org/v2/top-headlines?' +
      'country=jp&' +
      'apiKey=(自分のAPIKey)';
    fetch(url)
      .then(response => response.json())
      .then(result => {
        setData(result.articles);
        isLoaded(true);
      });
  }

  React.useEffect(() => {
    getNews();
  }, []);

  const keyExtractor = (item, index) => index.toString();
  const renderItem = ({ item }) => (
    <ListItem
      onPress={() => {
        navigation.navigate('Web', { url: item.url, title: item.title });
      }}
      title={item.title}
      subtitle={() => <Text>{item.publishedAt.substr(0, 10)}</Text>}
      leftAvatar={() => {
        if (item.urlToImage !== null) {
          return <Avatar size="large" source={{ uri: item.urlToImage }} />;
        } else {
          return (
            <Avatar
              size="large"
              overlayContainerStyle={{ backgroundColor: '#555' }}
              rounded
              icon={{ name: 'file-o', color: '#ffe', type: 'font-awesome' }}
            />
          );
        }
      }}
      bottomDivider
      chevron
    />
  );

  const _onRefresh = React.useCallback(() => {
    setRefresh(true);
    getNews();
    setRefresh(false);
  },[refresh]);

  if (!load) {
    return (
      <View style={{ flex: 1, justifyContent: 'center' }}>
        <ActivityIndicator size="large" color="#0000ff" />
      </View>
    );
  }

  return (
    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
      <ScrollView style={{width:"100%"}}
      refreshControl={
        <RefreshControl refreshing={refresh} onRefresh={() => _onRefresh()} />
      }>
        <FlatList
          keyExtractor={keyExtractor}
          data={data}
          renderItem={renderItem}
        />
      </ScrollView>
    </View>
  );
}


function showNews({navigation,route}) {
  React.useEffect(() => {
    navigation.setOptions({
      title:route.params.title
    })
  },[navigation]);
  return (
  <WebView source={{ uri: route.params.url }} />
  )
}

const NewsStack = createStackNavigator();

function stackFirstRoot() {
  return ( 
    <NavigationContainer>
      <NewsStack.Navigator>
                <NewsStack.Screen
                  name="NewsList"
                  component={NewsList}
                  options={{
                    headerStyle:{
                      backgroundColor:"#5bc0de"
                    },
                    headerTintColor:"white",
                    headerTitleStyle:{
                      fontWeight:"bold"
                    },
                    headerTitleAlign:"center"
                  }}
                />
                <NewsStack.Screen name="Web" 
                  component={showNews}
                  options={{
                    headerStyle:{
                      backgroundColor:"#5bc0de"
                    },
                    headerTintColor:"white",
                    headerTitleStyle:{
                      fontWeight:"bold"
                    },
                    headerTitleAlign:"center"
                }}/>
      </NewsStack.Navigator>
    </NavigationContainer>
  )
}
export default stackFirstRoot;

解説としては、
まずScrollViewの属性に、refreshcontrolを指定します。
refreshcontrolの返り値には、RefreshControlコンポーネントを指定します。
こうすることで、とりあえず「画面を引っ張る」の機能は持たせることができます。

RefreshControlの引数では、
refreshing:更新アイコンの表示
onRefresh:画面を引っ張ったときの動作
という役割があります。

今回、onRefreshには

  1. refreshingをtrueにする
  2. 再度getNews()を実行
  3. refreshingをfalseにする

という中身を持たせています。
こうすることで、更新中にアイコンを表示し、ニュースを取得し終えたらアイコンを非表示にすることができます。

実際の動き

React Native入門⑦ 画面を引っ張って更新できるようにする【2020】
こんな感じになります。
ニュースは短時間に多くは更新されないので今回の例では更新されていませんが、
30分くらいたった後画面を引っ張ると更新されます。

まとめ

ニュースアプリに更新機能を持たせました。
かなり便利なコンポーネントですね。

スポンサーリンク