5-2 將天氣資料呈現於畫面中 - useState 的使用
本單元對應的專案分支為:create-current-weather-state
。
#
單元核心這個單元的主要目標包含:
- 根據畫面設計所需要的資料欄位
- 使用
useState
定義並使用所需的資料狀態
在上一個單元中,我們已經申請了使用中央氣象局 API 的授權碼,並且說明了在「臺灣好天氣」這個專案中會使用到的兩支 API。在實際向中央氣象局 API 發送請求前,會先在 React 元件中定義會使用到的資料狀態,並把這些資料呈現在畫面上,等到資料能正確在畫面上顯示後,才會在實際串接 API 取得的資料。
#
使用 useState 定義資料狀態首先根據我們設計的畫面,可以先規劃所需要的資料欄位有哪些:
接著便可以開始透過 useState
來定義這些所需要的資料欄位:
tip
小提醒:在帶入資料時,並不是完全憑空捏照,而是參考 API 給的回應格式填入。
#
將資料狀態帶入 JSX 中接著我們就把這些資料帶入到 JSX 中原本寫死數值的地方:
可以看到,原本寫死在 JSX 中的資料,現在都改成用 useState
產生的 currentWeather
這個物件,這樣未來只要 currentWeather
內的資料有改變時,React 就會自動幫我們更新畫面。
#
優化資料呈現現在我們看到的溫度(temperature
)會出現小數點,而最後觀測時間(observationTime
)則不是我們習慣的格式,我們針對這個部分來進行優化。
#
溫度針對溫度的部分,可以使用 Math.round()
做四捨五入。改成這樣:
#
最後觀測時間對於最後觀測時間,我們得到的資料是 2020-12-12 22:10:00
,我們希望可以顯示 下午10:10
這樣就好。
要達到這個效果的做法有很多,這裡我們可以使用瀏覽器原生的 Intl 這個方法,這個方法的全名是 Internationalization API,它可以針對日期、時間、數字(貨幣)等資料進行多語系的呈現處理,相當方便,我們可以先將 <Refresh>
中的程式碼改成:
提醒
這裡你會看到 {' '}
的用法,這是因為在 JSX 中預設的空格最後在網頁呈現時都會被過濾掉,因此如果你希望最後在頁面上元件與元件間是留有空格的,就可以透過帶入「空字串」的方式來加入空格。
在 Intl.DateTimeFormat(<地區>, <設定>)
這個方法中
- 第一個參數放的是地區,台灣的話使用
zh-TW
。 - 第二個參數放的是一些設定值,例如我們希望以數值呈現「時」和「分」就好
- 最後透過
.format(<時間>)
把時間帶進去之後,就會看到格式化後的時間
補充
關於 Intl
這個方法,有興趣的話可以進一步參考 MDN 官方文件的說明:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl
現在當我們透過 npm start
把專案啟動時,就會看到「溫度」和「觀測時間」的顯示方式比之前的樣子更友善:
#
處理跨瀏覽器問題現在當我們使用 Chrome 或 Firefox 開啟這個頁面時,並不會出現任何錯誤,但若你是 Safari 的使用者(在 iOS 行動裝置大多都是使用 Safari),將會看到如下錯誤訊息,並顯示 RangeError: date value is not finite in DateTimeFormat format()
:
之所以會有這個錯誤產生,是因為我們從中央氣象局取得的時間資料是 2020-12-12 10:31:00
這樣的格式,當我們使用 new Date('2020-12-12 10:31:00')
試著把這個時間轉成合法的 JavaScript 時間物件時,在 Chrome 或 Firefox 是可以的,但在 Safari 並不支援這種用法。
你可以在各瀏覽器開發者工具的 console
面板中輸入:
在幾個瀏覽器中會得到不同的回應:
你會發現就 Safari 最特別...硬是跟你說這是無效的日期格式。沒錯,跨瀏覽器問題永遠是每個前端工程師心中最軟的那一塊。
好在這個問題並不難處理,因為時間的內容算是大大小小的網站都會用到的東西,所以通常已經有許多開發者一起開發開源套件,讓大家都可以用更簡便且支援跨瀏覽器的方式來處理這些問題。
#
安裝 dayjs這裡我們使用一個很輕量的時間處理工具,稱作 dayjs,安裝的方式你應該不陌生了,在終端機中輸入:
#
使用 dayjs 處理跨瀏覽器時間問題dayjs 的功能很多,這裡我們先單純用來處理跨瀏覽器的問題。要使用這個工具前,一樣要先記得載入:
接著在原本使用 new Date()
將日期字串轉換成 JavaScript 日期物件的地方,改成使用 dayjs()
,也就是將 .format(new Date(...))
改成 .format(dayjs(...))
:
改用 dayjs
後世界再次恢復了和平,現在在 Safari 中也可以正確解析日期格式。
#
換你了!使用 useState 定義資料狀態現在要換你在 App 元件中定義畫面中會使用到的資料狀態。同樣可以參考下面的流程:
- 使用 useState 取得「資料狀態(
currentWeather
)」和「修改資料狀態(setCurrentWeather
)」的方法 - 根據畫面中所需要的資料,以及 API 回應資料 ,在
currentWeather
中定義各資料欄位預設值 - 把原本寫死在 JSX 中的資料改成透過
currentWeather
這個資料狀態來呈現 - 優化「溫度」和「觀測時間」的顯示
- 處理時間在跨瀏覽器上的問題
本單元相關之網頁連結、完整程式碼與程式碼變更部分可於 create-current-weather-state
分支檢視: https://github.com/pjchender/learn-react-from-hook-realtime-weather-app/tree/create-current-weather-state
另外由於專案實作的程式碼較為複雜,再次提醒讀者在每一個單元中都可以善加利用 Github 上的「時鐘」圖示來檢視每個單元程式碼的變化:
在 commit 中將會清楚呈現每個單元程式碼的變化: