iT邦幫忙

2023 iThome 鐵人賽

DAY 20
0

上篇文章已經透過 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 中更換,而不用去修改程式碼。

使用 API

接下來就可以在 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 了。下一篇文章就來介紹怎麼傳遞資料,明天見 👋!


上一篇
Day 19 - 簡單定位 - Expo Location
下一篇
Day 21 - 使用 Zustand 管理狀態
系列文
掌握 React Native 與 Expo:30天雙打,新手也能精通跨平台開發!30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言