7-1 處理不同支 API 需帶入不同地區名稱的問題

本單元對應的專案分支為:create-available-locations-data

單元核心#

這個單元的主要目標包含:

  • 建立各 API 所需使用的 locationName 對應表
  • 撰寫 findLocation 函式,以取得拉取 API 資料時所需使用的 locationName

現在「臺灣好天氣」雖然功能看似一切正常了,但使用者並沒有辦法自由選擇想要切換的地區,因此勢必需要多一個設定頁面,讓使用者可以在「天氣資訊頁」和「設定頁」間來回切換:

Imgur

在這個章節中將會練習:

  1. 透過條件渲染的方式來達到「切換頁面」的效果
  2. 了解表單(form)在 React 中的兩種不同使用方式(controlled vs uncontrolled)
  3. useRef 這個 React Hooks 的使用
  4. 瀏覽器 localStorage 的使用

讓我們依序看下去。

不同支 API 需要帶入的地區名稱不同#

但在開始實作這個設定頁面前,需要先來處理之前一直提到的問題-「天氣觀測」和「天氣預報」這兩支 API 需要帶入的地區名稱不同(locationName)。

也就是說,同樣想拉取「臺北市」的天氣資料時,在「天氣預報 API」的 locationName 需要帶入「臺北市」,但在「天氣觀測 API」中需要帶入的是「臺北」。

這也就是為什麼目前在 App.js 中,雖然同樣是要搜尋「臺北市」的資料,但卻分別訂了 LOCATION_NAME(臺北)和 LOCATION_NAME_FORECAST(臺北市)這兩個常數:

// ./src/App.js
// ...
const LOCATION_NAME = '臺北';
const LOCATION_NAME_FORECAST = '臺北市';
const App = () => {
/* ... */
};

另外,一個縣市內也會有許多不同的局屬氣象站,但因為目前臺灣好天氣的設計上,只會讓使用者選擇一個縣市,而不會再細分各縣市內的區域,因此我們只能選擇一個最具代表性的局屬氣象站來代表該縣市。舉例來說,雖然使用者選擇「苗栗縣」,但因苗栗縣有許多不同鄉鎮區,這裡我們在資料呈現時只會挑其中一個鄉鎮的資料來呈現。

建立不同 API 的地區名稱對應表#

和前幾個單元中會特別整理「日出日落」和「天氣型態對應圖示」的資料一樣,這裡我們同樣需要整理出一張對應表,用來處理不同支 API 所需的不同地區名稱來進行查詢,這裡我們先定義一個名為 availableLocations 的物件,把所有可查詢到的地區都放在內,其中:

  • cityName 指的是縣市的名稱,可以對應到「天氣預報」的地區名稱
  • locationName 指的是觀測站所在地區,可以對應到「天氣觀測」的地區名稱
  • sunriseCityName 則是對應到「日落日出時間」的地區名稱
// 完整的程式碼放置於該單元的 Github 分支說明頁
const availableLocations = [
{
cityName: '宜蘭縣',
locationName: '宜蘭',
sunriseCityName: '宜蘭縣',
},
{
cityName: '嘉義市',
locationName: '嘉義',
sunriseCityName: '嘉義市',
},
// ...
];

讀者可以到本單元在 Github 上對應的分支(create-available-locations-data)說明頁複製完整的程式碼:

Imgur

並把 availableLocations 物件,複製貼上到 ./src/utils/helpers.js 檔案中。這裡透過 export 可以把 availableLocations 匯出,讓其他支 JavaScript 檔案可以透過 import 載入此變數:

Imgur

補中
  • 中央氣象局另外還有提供「自動氣象站-氣象觀測資料」的觀測資料,可以拿到更精細的地區天氣資訊,但涉及更複雜的資料處理,並非本書著墨的重點,因此有興趣的讀者未來可以自行取用。
  • 目前「天氣預測」和「日出日落」使用的 locationName 值是一樣的,但因為過去曾有不同的情況,因此這裡還是分成 cityNamesunriseCityName 兩個不同欄位。

建立取得地區名稱的函式#

接著前面單元中定義的 getMoment 函式很類似,之前這個函式是讓使用者傳入 locationName 參數時,可以回傳當前的時間是屬於白天或晚上。

在之後的設定頁面中,主要會顯示「縣市」的列表讓使用者選擇,為了幫助我們可以從使用者選擇的「縣市名稱」中快速找到該地區在各個 API 所對應需要帶入的 locationName,因此同樣需要定義一個函式來處理這件事。

./src/utils/helpers.js 的檔案中,定義一個名為 findLocation 的函式,這個函式的參數只需帶入縣市名稱(cityName),就可以找出在 availableLocations 中對應物件後回傳 :

// ./src/utils/helpers.js
// ...
export const availableLocations = [
/* ... */
];
export const findLocation = (cityName) => {
return availableLocations.find((location) => location.cityName === cityName);
};

現在假設使用者選擇的是「嘉義市」時,透過 findLocation 函式,就可以找到各個 API 需要對應帶入的 locationName 為何:

const currentLocation = findLocation('嘉義市');
// currentLocation 會得到
// {
// cityName: '嘉義市',
// locationName: '嘉義',
// sunriseCityName: '嘉義市',
// };

換你了!建立地區名稱對應表#

這個單元主要是為了處理不同支 API 需要使用的 locationName 不同,因此建立了一個 availableLocations 的物件,從中可以查詢不同 API 需要帶入的 locationName。另外,建立了一個名為 findLocation 方法,方便後續可以快速從 availableLocations 中找出需要的地區名稱。

現在要請你:

  • 到本單元 Github 的分支說明頁,複製 availableLocations 陣列
  • availableLocation 貼上到 ./src/utils/helpers
  • 新增 findLocation 這個方法,可以接收參數 cityName ,並回傳 availableLocations 對應地區的物件。

本單元相關之網頁連結、完整程式碼與程式碼變更部分可於 create-available-locations-data 分支檢視:https://github.com/pjchender/learn-react-from-hook-realtime-weather-app/tree/create-available-locations-data

Imgur