上篇文章已經透過 Expo Location 取得目前所在地的經緯度,接下來就可以使用 OpenWeatherMap API 來取得目前的天氣資訊。
.env
管理 API 資訊由於我們需要使用 API Key 來取得天氣資訊,但是這個 API Key 如果直接放在程式碼中的話,之後專案如果上傳到 GitHub 的話,就會有安全性的問題,所以我們可以使用 .env
來管理 API Key。
首先在專案的根目錄新增一個 .env
檔案:
$ touch .env
然後在 .env
中加入 API Key,順便連 API URL 都一起放進去:
在 Expo 專案中,如果要放入資料進
.env
的話,只要在前面加上前綴字PUBLIC
就可以了。
EXPO_PUBLIC_WEATHER_API_URL=https://api.openweathermap.org/data/3.0/onecall?
EXPO_PUBLIC_WEATHER_API_KEY=放入你的 API Key
這樣子之後如果要更換 API Key 的話,就可以直接在 .env
中更換,而不用去修改程式碼。
接下來就可以在 App.tsx
中使用 API 了,這裡我們使用 fetch
來取得資料,並且使用 useEffect
來取得資料。
在 Expo 專案中,如果要使用
.env
的資料的話,就要使用process.env
來取得資料。
import { useEffect, useState } from 'react'
import * as Location from 'expo-location'
export default function App() {
const apiUrl = process.env.EXPO_PUBLIC_WEATHER_API_URL
const apiKey = process.env.EXPO_PUBLIC_WEATHER_API_KEY
const [location, setLocation] = useState<Location.LocationObject | null>(null)
const [errorMsg, setErrorMsg] = useState<string | null>('')
const fetchWeatherData = async () => {
if (location && location.coords) {
const { latitude, longitude } = location.coords
try {
const response = await fetch(
`${apiUrl}lat=${latitude}&lon=${longitude}&exclude=hourly,daily&appid=${apiKey}`
)
const json = await response.json()
console.log(json)
} catch (err) {
console.log(err)
}
}
}
useEffect(() => {
;(async () => {
let { status } = await Location.requestForegroundPermissionsAsync()
if (status !== 'granted') {
setErrorMsg('Permission to access location was denied')
return
}
let location = await Location.getCurrentPositionAsync({})
setLocation(location)
})()
}, [])
useEffect(() => {
if (location) {
fetchWeatherData()
}
}, [location])
return <SafeAreaView className='flex-1 bg-blue-500'>// 省略</SafeAreaView>
}
這裡搭配 Expo Location 取得經緯度,並且使用 fetch
來取得天氣資訊,沒意外的話,應該會在 console 中看到目前經緯度的天氣資訊。
但是有幾點值得注意的部分,目前拿到的資料,像是溫度、體感溫度都是以 K(Kelvin)為單位,這跟我們平常使用的攝氏溫度不太一樣,所以我們需要把這些資料轉換成攝氏溫度。
根據 OpenWeatherMap API 文件 的說明,我們可以使用 units
來轉換溫度,預設是使用 standard
,也就是 K(Kelvin),我們可以使用 metric
來轉換成攝氏溫度。
所以我們可以把 API URL 改形式:
const response = await fetch(`${apiUrl}lat=${latitude}&lon=${longitude}&exclude=hourly,daily&units=metric&appid=${apiKey}`)
這樣子就可以拿到攝氏溫度的資料了。
然後設定一個 state 存放只需要的資料,這裡我們只需要目前的溫度、體感溫度、天氣狀況,所以我們可以定義 interface 來定義這些資料的型別:
interface WeatherDetail {
description: string
icon: string
id: number
main: string
}
interface CurrentWeatherInfo {
feels_like: number
temp: number
weather: WeatherDetail[]
}
export default function App() {
const apiUrl = process.env.EXPO_PUBLIC_WEATHER_API_URL
const apiKey = process.env.EXPO_PUBLIC_WEATHER_API_KEY
const [location, setLocation] = useState<Location.LocationObject | null>(null)
const [errorMsg, setErrorMsg] = useState<string | null>('')
const [currentWeather, setCurrentWeather] =
useState<CurrentWeatherInfo | null>(null)
console.log(currentWeather)
const fetchWeatherData = async () => {
if (location && location.coords) {
const { latitude, longitude } = location.coords
try {
const response = await fetch(
`${apiUrl}lat=${latitude}&lon=${longitude}&exclude=hourly,daily&units=metric&appid=${apiKey}`
)
const json = await response.json()
setCurrentWeather(json.current)
} catch (err) {
console.log(err)
}
}
}
useEffect(() => {
;(async () => {
let { status } = await Location.requestForegroundPermissionsAsync()
if (status !== 'granted') {
setErrorMsg('Permission to access location was denied')
return
}
let location = await Location.getCurrentPositionAsync({})
setLocation(location)
})()
}, [])
useEffect(() => {
if (location) {
fetchWeatherData()
}
}, [location])
return <SafeAreaView className='flex-1 bg-blue-500'>// 省略</SafeAreaView>
}
最後就拿到我們需要的資料了,有了這些資料,接下來就可以把資料傳遞到各個 component 了。下一篇文章就來介紹怎麼傳遞資料,明天見 👋!