按照進度,這篇文章會示範怎麼從 OpenWeatherMap 取得未來數小時的天氣預報,並且讓資料展示在畫面上。
首先必須要先知道資料有哪些,以及怎麼取得。按照OpenWeatherMap 文件,可以看到有提供 hourly
的資料,並且是以每小時為單位,最多提供 48 小時的資料。
不過我們應該只需要取得“需要”的資料就好,而 OpenWeatherMap 提供了一個參數,讓我們可以去過濾不需要的資料,這個參數就是 exclude
。
exclude
可以設定為以下幾種:
current
:目前天氣minutely
:每分鐘天氣hourly
:每小時天氣daily
:每日天氣alerts
:天氣警報這裡我們暫時只需要 hourly
跟 current
,所以 exclude
設定為 daily,minutely,alerts
。
了解完 API 之後,我們就可以開始設定狀態了。首先,我們需要一個狀態來存放未來數小時的天氣預報,這裡我們使用 hourlyWeather
來表示,並設定型別:
interface HourlyWeatherInfo {
dt: number
temp: number
weather: WeatherDetail[]
readableTime: string
}
interface Store {
// 省略其他程式碼
hourlyWeather: HourlyWeatherInfo[] | null
}
const useStore = create<Store>((set) => ({
// 省略其他程式碼
hourlyWeather: null,
fetchWeatherData: async () => {
const { location, errorMsg } = useStore.getState()
if (location && location.coords) {
const { latitude, longitude } = location.coords
const apiUrl = process.env.EXPO_PUBLIC_WEATHER_API_URL
const apiKey = process.env.EXPO_PUBLIC_WEATHER_API_KEY
try {
const response = await fetch(
`${apiUrl}lat=${latitude}&lon=${longitude}&exclude=minutely,daily,alerts&units=metric&appid=${apiKey}`
)
const json = await response.json()
set({
currentWeather: json.current
})
} catch (err) {
console.log(err)
}
}
}
}))
看一下下面圖片需要展示什麼資料:
所以我們在 HourlyWeatherInfo
中,需要 dt
、temp
、weather
、readableTime
這幾個資料,其中 dt
是時間戳記,temp
是溫度,weather
是天氣資料,readableTime
是可讀的時間。
由於需要展示可讀的時間,所以我們需要將時間戳記轉換成可讀的時間,這裡我們使用上一篇文章介紹的 dayjs
來轉換時間戳記:
import dayjs from 'dayjs'
const convertHourlyToReadableTime = (
hourlyData: HourlyWeatherInfo[],
sliceCount: number = 5
) => {
return hourlyData.slice(1, sliceCount).map((hour: HourlyWeatherInfo) => {
const readableTime = dayjs.unix(hour.dt).format('HH:mm')
return { ...hour, readableTime }
})
}
這裡我們使用 dayjs.unix
來轉換時間戳記,並且設定格式為 HH:mm
。而且因為時間資料有 48 筆,我們不需要這麼多,所以使用 slice
來過濾掉不需要的資料,先取得 4 筆資料就好。
但是眼尖的你可能會發現,這裡的 slice
是從 1
開始,而不是 0
,這是因為第一筆資料是目前時間的天氣,所以我們不需要這筆資料。
接下來就可以從 fetchWeatherData()
中取得資料,並且轉換成可讀的時間:
const useStore = create<Store>((set) => ({
// 省略其他程式碼
fetchWeatherData: async () => {
const { location, errorMsg } = useStore.getState()
if (location && location.coords) {
const { latitude, longitude } = location.coords
const apiUrl = process.env.EXPO_PUBLIC_WEATHER_API_URL
const apiKey = process.env.EXPO_PUBLIC_WEATHER_API_KEY
try {
const response = await fetch(
`${apiUrl}lat=${latitude}&lon=${longitude}&exclude=minutely,daily&units=metric&appid=${apiKey}`
)
const json = await response.json()
set({
currentWeather: json.current,
hourlyWeather: convertHourlyToReadableTime(json.hourly)
})
} catch (err) {
console.log(err)
}
}
},
}))
這裡我們使用 convertHourlyToReadableTime()
取得來自 hourly
的資料。
最後在 App.tsx
中,從 useStore
中取得 hourlyWeather
,並且將資料傳遞給 HourlyWeather
:
export default function App() {
const {
location,
errorMsg,
setLocation,
setErrorMsg,
fetchWeatherData,
fetchLocation,
hourlyWeather
} = useStore()
// 省略其他程式碼
return (
<SafeAreaView className='flex-1 bg-blue-500'>
<StatusBar style='auto' />
<HeaderInfo />
<CurrentWeather />
<View className='flex-row justify-around p-6'>
{hourlyWeather?.map((hourly) => {
const { temp, readableTime, dt } = hourly
return <HourlyForecast time={readableTime} icon="cloudy" temp={temp} key={dt} />
})}
</View>
// 省略其他程式碼
</SafeAreaView>
)
}
最後記得將 HourlyWeather
的型別修正,並放入 props:
interface HourlyForecastProps {
time: string
icon: keyof typeof weatherIcons
temp: number
}
const HourlyForecast: FC<HourlyForecastProps> = ({ time, icon, temp }) => {
const IconComponent = weatherIcons[icon]?.component || AntDesign || Feather
const iconName = weatherIcons[icon]?.name || 'question'
const iconColor = weatherIcons[icon]?.color || '#ffffff'
return (
<View className='items-center space-y-2'>
<Text className='text-sm font-medium text-white'>{time}</Text>
<IconComponent name={iconName} size={30} color={iconColor} />
<Text className='text-lg font-semibold text-white'>{temp}°</Text>
</View>
)
}
這樣就可以在畫面上看到未來數小時的天氣預報了: