เราอยู่ในโลกที่เปลี่ยนแปลงตลอดเวลา หากคุณต้องการติดตามข่าวสารให้ทันเหตุการณ์ แอปข่าวที่ดีจึงเป็นสิ่งจำเป็น
ในบทความนี้ เราจะสร้างแอปพลิเคชันข่าวสำหรับ Android โดยใช้ React Native เพื่อช่วยให้คุณเรียนรู้เทคโนโลยีที่น่าสนใจและอยู่ในข่าวเสมอ แอปนี้จะดึงหัวข้อข่าวจากแหล่งข่าวต่างๆ และแสดงตามหมวดหมู่

นี่คือรูปแบบของแอปเมื่อเสร็จสมบูรณ์ มาเริ่มกันเลย
วิธีติดตั้ง Expo
Expo คืออะไร? Expo เป็นเฟรมเวิร์กที่ช่วยให้คุณสร้างและปรับใช้แอป React Native ได้อย่างรวดเร็วและง่ายดาย
มาติดตั้งกัน
npm install --global expo-cliรันคำสั่งนี้ในเทอร์มินัลเพื่อติดตั้ง Expo CLI โดยใช้ --global เพื่อให้ติดตั้งทั่วระบบ
หลังจากติดตั้งเสร็จ เราต้องสร้างโปรเจกต์ Expo
expo init News-Applicationใช้คำสั่งด้านบนเพื่อเริ่มต้นโปรเจกต์ ระบบจะถามรายละเอียด เช่น ชื่อแอป การใช้ TypeScript หรือเริ่มจากโปรเจกต์ว่าง ให้เลือก blank แล้วกด Enter
ระบบจะดาวน์โหลดแพ็กเกจและ dependencies ทั้งหมด เมื่อเสร็จแล้ว ให้เข้าโฟลเดอร์โปรเจกต์ และพิมพ์ expo start เพื่อเปิดเครื่องมือนักพัฒนาในเบราว์เซอร์

ด้านซ้ายจะมีตัวเลือก เช่น รันบนอุปกรณ์ Android/Emulator หรือ iOS Simulator เราจะรันบนเว็บเบราว์เซอร์โดยคลิก Run in Web Browser
import { StatusBar } from 'expo-status-bar'; import React from 'react'; import { StyleSheet, Text, View } from 'react-native'; export default function App() { return ( <View style={styles.container}> <Text>Open up App.js to start working on your app!</Text> <StatusBar style="auto" /> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#fff', alignItems: 'center', justifyContent: 'center', }, }); นี่คือไฟล์ App.js เริ่มต้นที่มีโค้ดพื้นฐาน

ตอนนี้แอปพลิเคชันของเรากำลังทำงานอยู่แล้ว
สร้างหน้าจอต่างๆ ด้วย React Navigation
ต่อไป เราจะสร้างหน้าจอหลายหน้าสำหรับแอปพลิเคชัน โดยใช้ React Navigation มาติดตั้งกัน
ไปที่ https://reactnavigation.org/ และคลิก Read Docs เพื่อเปิดหน้าเอกสาร
ติดตั้ง React Navigation ด้วยคำสั่ง:
npm install @react-navigation/native expo install react-native-screens react-native-safe-area-contextเราจะใช้ bottomTabNavigator จากเมนูซ้ายเลือก API Reference > Navigators > Bottom Tabs

ติดตั้ง Bottom Tabs:
npm install @react-navigation/bottom-tabsใน App.js ให้นำเข้า Bottom Tabs:
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; นำเข้า Tab Screens:
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; import { NavigationContainer } from '@react-navigation/native'; const Tab = createBottomTabNavigator(); function MyTabs() { return ( <Tab.Navigator> <Tab.Screen name="Home" component={HomeScreen} /> <Tab.Screen name="Settings" component={SettingsScreen} /> </Tab.Navigator> ); }สำหรับแอปของเรา เราต้องการหน้าจอดังนี้:
<Tab.Navigator> <Tab.Screen name="All" component={All} /> <Tab.Screen name="Business" component={Business} /> <Tab.Screen name="Health" component={HealthScreen} /> <Tab.Screen name="Sports" component={SportsScreen} /> <Tab.Screen name="Tech" component={TechScreen} /> </Tab.Navigator>เราต้องสร้างหน้าจอสำหรับแท็บ: All News, Business News, Sports News, Health News, และ Tech News พร้อมสร้างคอมโพเนนต์สำหรับแต่ละหน้าจอในโปรเจกต์
ห่อ TabNavigator ไว้ใน NavigationContainer:
<NavigationContainer> <Tab.Navigator> <Tab.Screen name="All" component={All} /> <Tab.Screen name="Business" component={Business} /> <Tab.Screen name="Health" component={HealthScreen} /> <Tab.Screen name="Sports" component={SportsScreen} /> <Tab.Screen name="Tech" component={TechScreen} /> </Tab.Navigator> </NavigationContainer>นำเข้าโมดูลหน้าจอทั้งหมด:
import All from './screens/All'; import Business from './screens/Business'; import HealthScreen from './screens/Health'; import SportsScreen from './screens/Sports'; import TechScreen from './screens/Tech';รวมโค้ดทั้งหมด:
import React from 'react'; import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; import { NavigationContainer } from '@react-navigation/native'; import All from './screens/All'; import Business from './screens/Business'; import HealthScreen from './screens/Health'; import SportsScreen from './screens/Sports'; import TechScreen from './screens/Tech'; const Tab = createBottomTabNavigator(); export default function App() { return ( <NavigationContainer> <Tab.Navigator> <Tab.Screen name="All" component={All} /> <Tab.Screen name="Business" component={Business} /> <Tab.Screen name="Health" component={HealthScreen} /> <Tab.Screen name="Sports" component={SportsScreen} /> <Tab.Screen name="Tech" component={TechScreen} /> </Tab.Navigator> </NavigationContainer> ); } ผลลัพธ์จะได้ 5 หน้าจอ:

ตอนนี้เรามี 5 หน้าจอ เราจะปรับไอคอนสำหรับ Bottom Tabs โดยใช้ไลบรารีไอคอน react-native-elements
ติดตั้งด้วยคำสั่ง:
npm install react-native-elementsแพ็กเกจนี้มีไอคอนให้เลือกมากมาย

เพิ่มไอคอนใน Bottom Tab Navigator:
<Tab.Screen name="All" component={All} options={{ tabBarIcon: (props) => ( <Icon type='feather' name='home' color={props.color} /> ), }} />เราเพิ่มไอคอน "home" ประเภท feather สำหรับหน้าแรก

ทำซ้ำสำหรับแท็บอื่นๆ:
<Tab.Navigator> <Tab.Screen name="All" component={All} options={{ tabBarIcon: (props) => ( <Icon type='feather' name='home' color={props.color} /> ), }} /> <Tab.Screen name="Business" component={Business} options={{ tabBarIcon: (props) => ( <Icon type='feather' name='dollar-sign' color={props.color} /> ), }} /> <Tab.Screen name="Health" component={HealthScreen} options={{ tabBarIcon: (props) => ( <Icon type='feather' name='heart' color={props.color} /> ), }} /> <Tab.Screen name="Sports" component={SportsScreen} options={{ tabBarIcon: (props) => ( <Icon type='ionicon' name="tennisball-outline" color={props.color} /> ), }} /> <Tab.Screen name="Tech" component={TechScreen} options={{ tabBarIcon: (props) => ( <Icon type='ionicon' name="hardware-chip-outline" color={props.color} /> ), }} /> </Tab.Navigator>
ตอนนี้แต่ละแท็บมีไอคอนเฉพาะตัวแล้ว
เรียกใช้ News API
เราจะเรียก News API จาก https://newsapi.org/

สมัครสมาชิกเว็บไซต์เพื่อรับ API Key
สร้างไฟล์ config เพื่อเก็บค่าคงที่ของข่าว:
export const API_KEY = ``; export const endpoint = `https://newsapi.org/v2/top-headlines`; export const country = 'in'เราต้องการ API_KEY, endpoint, และรหัสประเทศ
สร้างบริการสำหรับ GET API Request ในไฟล์ services.js
นำเข้า config ที่ด้านบน:
import { API_KEY, endpoint, country } from '../config/config';เขียนฟังก์ชันบริการ:
export async function services(category = 'general') { let articles = await fetch(`${endpoint}?country=${country}&category=${category}`, { headers: { 'X-API-KEY': API_KEY } }); let result = await articles.json(); articles = null; return result.articles; }เราดึงข้อมูลข่าวโดยใช้ endpoint พร้อมพารามิเตอร์ country และ category ฟังก์ชันรับ category เป็น general เป็นค่าเริ่มต้น ส่ง API Key ใน headers แปลง response เป็น JSON และคืนค่า articles
ไฟล์เต็มสำหรับอ้างอิง:
import { API_KEY, endpoint, country } from '../config/config'; export async function services(category = 'general') { let articles = await fetch(`${endpoint}?country=${country}&category=${category}`, { headers: { 'X-API-KEY': API_KEY } }); let result = await articles.json(); articles = null; return result.articles; }นำเข้า service ใน All.js:
import { services } from '../services/services';ใช้ Hooks useState และ useEffect useEffect จะเรียก service และ useState จะเก็บ response จาก API
import React, { useEffect, useState } from 'react' import { View } from 'react-native'; import { services } from '../services/services'; export default function All() { const [newsData, setNewsData] = useState([]) useEffect(() => { services('general') .then(data => { setNewsData(data) }) .catch(error => { alert(error) }) }, []) return ( <View> </View> ) } ในไฟล์นี้ เราเรียก services ใน useEffect hook เก็บ response ใน state newsData (array) ส่งพารามิเตอร์ category เป็น general เนื่องจากหน้านี้แสดงข่าวทั้งหมด สำหรับหน้าอื่นจะเปลี่ยน category ตามนั้น เช่น health, sports เป็นต้น
ตอนนี้เราต้องแสดงข้อมูลใน UI ต้องใช้แพ็กเกจ Native Base มาติดตั้งกัน
ติดตั้ง Native Base:
yarn add native-base styled-components styled-system expo install react-native-svg react-native-safe-area-contextใน All.js นำเข้าจาก Native Base:
import React, { useEffect, useState } from 'react' import { View, Text } from 'react-native'; import { NativeBaseProvider, FlatList, ScrollView, Divider, Image, Spinner } from 'native-base'; import { services } from '../services/services';เพิ่ม NativeBaseProvider ใน return:
return ( <NativeBaseProvider> </NativeBaseProvider> )เพิ่ม ScrollView เพื่อให้เลื่อนได้เมื่อข่าวเยอะ:
<NativeBaseProvider> <ScrollView height={850}> </ScrollView> </NativeBaseProvider>เพิ่ม FlatList เพื่อแสดงข้อมูลข่าว:
<NativeBaseProvider> <ScrollView height={850}> <FlatList data={newsData} renderItem={({ item }) => ( <View> </View> )} keyExtractor={(item) => item.id} /> </ScrollView> </NativeBaseProvider>FlatList รับ prop data เป็น newsData state และส่งคืน item จาก renderItem คล้าย map ใน JavaScript มี keyExtractor เพื่อทำให้แต่ละ item unik
แสดงข้อมูลใน View:
<NativeBaseProvider> <ScrollView height={850}> <FlatList data={newsData} renderItem={({ item }) => ( <View> <View> </View> </View> )} keyExtractor={(item) => item.id} /> </ScrollView> </NativeBaseProvider>เพิ่ม Text ภายใน child view:
<NativeBaseProvider> <ScrollView height={850}> <FlatList data={newsData} renderItem={({ item }) => ( <View> <View> <Text> {item.title} </Text> <Text> {item.publishedAt} </Text> <Text> {item.description} </Text> </View> </View> )} keyExtractor={(item) => item.id} /> </ScrollView> </NativeBaseProvider>แสดงหัวข้อข่าว คำอธิบาย และวันที่เผยแพร่

จัดสไตล์แอปข่าว React Native
ตอนนี้แอปมีหัวข้อ คำอธิบาย และวันที่ แต่เราต้องจัดสไตล์ให้สวยงามขึ้น
นำเข้า StyleSheet จาก React Native:
import { View, Text, StyleSheet } from 'react-native';<View> <View style={styles.newsContainer}> <Text style={styles.title}> {item.title} </Text> <Text style={styles.date}> {item.publishedAt} </Text> <Text style={styles.newsDescription}> {item.description} </Text> </View> </View>เพิ่มสไตล์:
const styles = StyleSheet.create({ newsContainer: { padding: 10 }, title: { fontSize: 18, marginTop: 10, fontWeight: "600" }, newsDescription: { fontSize: 16, marginTop: 10 }, date: { fontSize: 14 }, });
แอปดูดีขึ้นแล้ว และเลื่อนได้อีกด้วย
เปลี่ยนรูปแบบวันที่ให้อ่านง่ายขึ้น เพราะ '2021-08-21T11:00:40Z' อ่านยาก เราจะใช้ moment.js
ติดตั้ง moment.js:
npm install moment --saveนำเข้าใน All.js และจัดรูปแบบ:
<Text style={styles.date}> {moment(item.publishedAt).format('LLL')} </Text>เลือกฟอร์แมต 'LLL' จากเอกสาร moment


ตอนนี้วันที่อ่านง่ายขึ้นแล้ว
เพิ่ม Divider แยกข่าวแต่ละรายการ:
<View> <View style={styles.newsContainer}> <Text style={styles.title}> {item.title} </Text> <Text style={styles.date}> {moment(item.publishedAt).format('LLL')} </Text> <Text style={styles.newsDescription}> {item.description} </Text> </View> <Divider my={2} bg="#e0e0e0" /> </View>
ข่าวถูกแยกด้วยเส้น Divider ดูเรียบร้อยแล้ว
News API มีรูปภาพด้วย มาเพิ่มกัน:
<View> <View style={styles.newsContainer}> <Image width={550} height={250} resizeMode={"cover"} source={{ uri: item.urlToImage, }} alt="Alternate Text" /> <Text style={styles.title}> {item.title} </Text> <Text style={styles.date}> {moment(item.publishedAt).format('LLL')} </Text> <Text style={styles.newsDescription}> {item.description} </Text> </View> <Divider my={2} bg="#e0e0e0" /> </View>ใช้ key urlToImage สำหรับรูปภาพ

ตอนนี้มีรูปภาพข่าวแสดงแล้ว
เพิ่ม Spinner แสดงสถานะกำลังโหลดข่าว
เพิ่ม Spinner ขณะโหลดข่าว
ตรวจสอบ ถ้า newsData length > 1 แสดง FlatList มิฉะนั้นแสดง Spinner
{newsData.length > 1 ? ( <FlatList data={newsData} renderItem={({ item }) => ( <View> <View style={styles.newsContainer}> <Image width={550} height={250} resizeMode={"cover"} source={{ uri: item.urlToImage, }} alt="Alternate Text" /> <Text style={styles.title}> {item.title} </Text> <Text style={styles.date}> {moment(item.publishedAt).format('LLL')} </Text> <Text style={styles.newsDescription}> {item.description} </Text> </View> <Divider my={2} bg="#e0e0e0" /> </View> )} keyExtractor={(item) => item.id} /> ) : ( <View style={styles.spinner}> <Spinner color="danger.400" /> </View> )}เพิ่มสไตล์สำหรับ Spinner:
spinner: { display: 'flex', justifyContent: 'center', alignItems: 'center', height: 400 }โค้ดเต็มของ All.js:
import React, { useEffect, useState } from 'react' import { View, Text, StyleSheet } from 'react-native'; import { NativeBaseProvider, FlatList, ScrollView, Divider, Image, Spinner } from 'native-base'; import { services } from '../services/services'; import moment from 'moment' export default function All() { const [newsData, setNewsData] = useState([]) useEffect(() => { services('general') .then(data => { setNewsData(data) }) .catch(error => { alert(error) }) }, []) return ( <NativeBaseProvider> <ScrollView height={850}> {newsData.length > 1 ? ( <FlatList data={newsData} renderItem={({ item }) => ( <View> <View style={styles.newsContainer}> <Image width={550} height={250} resizeMode={"cover"} source={{ uri: item.urlToImage, }} alt="Alternate Text" /> <Text style={styles.title}> {item.title} </Text> <Text style={styles.date}> {moment(item.publishedAt).format('LLL')} </Text> <Text style={styles.newsDescription}> {item.description} </Text> </View> <Divider my={2} bg="#e0e0e0" /> </View> )} keyExtractor={(item) => item.id} /> ) : ( <View style={styles.spinner}> <Spinner color="danger.400" /> </View> )} </ScrollView> </NativeBaseProvider> ) } const styles = StyleSheet.create({ newsContainer: { padding: 10 }, title: { fontSize: 18, marginTop: 10, fontWeight: "600" }, newsDescription: { fontSize: 16, marginTop: 10 }, date: { fontSize: 14 }, spinner: { display: 'flex', justifyContent: 'center', alignItems: 'center', height: 400 } });หน้า All.js เสร็จสมบูรณ์แล้ว เราสามารถนำโค้ดเดียวกันไปใช้ในหน้าอื่นได้ โดยเปลี่ยนพารามิเตอร์ใน services ใส่ useEffect hook
สำหรับหน้า Business ใช้ 'business', Health ใช้ 'health', Sports ใช้ 'sports', Tech ใช้ 'technology'
useEffect(() => { services('business') .then(data => { setNewsData(data) }) .catch(error => { alert(error) }) }, [])useEffect(() => { services('health') .then(data => { setNewsData(data) }) .catch(error => { alert(error) }) }, [])useEffect(() => { services('sports') .then(data => { setNewsData(data) }) .catch(error => { alert(error) }) }, [])useEffect(() => { services('technology') .then(data => { setNewsData(data) }) .catch(error => { alert(error) }) }, [])สรุป
ยินดีด้วย! แอปพลิเคชันข่าวของเราเสร็จสมบูรณ์แล้ว
ลองสร้างและทดลองปรับแต่งดู มีอะไรให้ทำอีกมากมาย
ดูเพลย์ลิสต์สร้างแอปข่าวด้วย React Native และ Native Base บนช่อง YouTube ของผม
ดาวน์โหลดโค้ดได้ที่: https://github.com/nishant-666/React-Native-News
Happy Learning.