感謝 iT 邦幫忙與博碩文化,本系列文章已出版成書「從 Hooks 開始,讓你的網頁 React 起來」,首刷版稅將全額贊助 iT 邦幫忙鐵人賽,歡迎前往購書,鼓勵筆者撰寫更多優質文章。
昨天我們已經把「即時天氣 App」發佈到 Github Pages 上了並且正名為「臺灣好天氣」。
但是這類型的天氣 App 如果可以安裝到手機上的話有多好呢?
今天就讓我們來看看如何把「臺灣好天氣」變成一個可以下載到手機裝置上的 Web App 吧!最後會列出一些 「那些重要但故意不告訴你的內容」 。如此,這一系列 30 天的鐵人賽也就圓滿了!筆者也差不多可以來好好休息圓寂了!
Progressive Web App (PWA) 中文稱作「漸進式網頁應用程式」,這是 Google 這幾年一直致力在推廣的網頁技術。第一次看到這個詞彙時就和我聽到 Application Programming Interface (API) 一樣一頭霧水。到底「漸進式」指的是什麼!?
簡單來說,PWA 在網頁的基礎上添加了許多功能,可以帶給使用者更好的瀏覽體驗,特別是在手機裝置上的感覺更佳明顯,讓使用者感覺上像是在開一個手機 App 而不是開啟網站。 PWA 的功能非常豐富,而漸進式的意思就是指你不用把這些功能一次全部到位,可以漸漸地一點一點加進去就可以。因為詳細的功能非常多,更多的說明可以參考 Google 和 MDN 的文件。
當我們透過 Create React App 來建立 React 應用程式時,Create React App 已經幫我們把許多 PWA 需要使用的工具都已經放進去了,只是需要我們手動開啟它。
首先進到專案中的 ./src/index.js
這支檔案, 將 PWA 中的 Service Worker 功能打開,只需把原本的 serviceWorker.unregister()
改成 serviceWorker.register()
即可:
Service Worker 算是在 PWA 中蠻核心的功能,它可以把網頁應用程式暫存(cache)下來,讓使用者下次點開的時候速度有感提升,並且可以讓這個網頁就像 App 一樣不用透過 App Store 就安裝在手機上,有需要的時候甚至可以在離線狀況下存取這個網站(但是當然就不能更新資料)。
因為現在可以讓使用者像是安裝 App 一樣,所以會需要使用到 App 的圖示,這些圖示同樣放在 Dropbox 上可供下載,在原本天氣圖示的檔案內,多了一個名為 app-icons
的資料夾,裡面放置了 App 需要用來顯示的圖示,把它們全部搬到 ./public/
資料夾內:
在這裏並不會用到太多其他的 PWA 功能,而是希望可以讓它看起來更像個原生的 App,並且可以下載到手機上使用。在專案建立好時 ./public
資料夾中已經有一支 manifest.json
,這裡會定義和這個 PWA 有端的說明,讓瀏覽器知道下載下來時要使用什麼 Logo、顯示什麼顏色等等。
在 ./public/manifest.json
中加入以下設定檔:
{
"short_name": "臺灣好天氣",
"name": "臺灣好天氣-即時縣市天氣",
"icons": [
{
"src": "icon@x48.png",
"type": "image/png",
"sizes": "48 × 48"
},
{
"src": "icon@96.png",
"type": "image/png",
"sizes": "96x96"
},
{
"src": "icon@144.png",
"type": "image/png",
"sizes": "144x144"
},
{
"src": "icon@192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "icon@512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
"display": "standalone",
"orientation": "portrait-primary",
"theme_color": "#1f2022",
"background_color": "#1f2022"
}
最後因為有些 PWA 的設定在 iOS 裝置上需要額外設定,因此我們需要把它們設定在 ./public/index.html
中:
<!-- ./public/index.html -->
<!DOCTYPE html>
<html lang="zh-Hant">
<head>
<meta charset="utf-8" />
<link rel="shortcut icon" href="%PUBLIC_URL%/icon@48.png" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, user-scalable=1.0, minimum-scale=1.0, maximum-scale=1.0, shrink-to-fit=no"
/>
<meta name="theme-color" content="#1f2022" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!-- PWA settings for ios device -->
<link rel="apple-touch-icon" href="%PUBLIC_URL%/icon@48.png" />
<link
rel="apple-touch-icon"
sizes="96x96"
href="%PUBLIC_URL%/icon@96.png"
/>
<link
rel="apple-touch-icon"
sizes="144x144"
href="%PUBLIC_URL%/icon@144.png"
/>
<link
rel="apple-touch-icon"
sizes="192x192"
href="%PUBLIC_URL%/icon@192.png"
/>
<link
rel="apple-touch-icon"
sizes="512x512"
href="%PUBLIC_URL%/icon@512.png"
/>
<link rel="apple-touch-startup-image" href="%PUBLIC_URL%/launch.png" />
<meta name="apple-mobile-web-app-title" content="臺灣好天氣" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="#1f2022" />
<meta name="description" content="臺灣好天氣-即時縣市天氣" />
<title>臺灣好天氣-即時縣市天氣</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
當我們都做好設定後,一樣只需要在使用 npm
的指令就可以發布到 Github 上了:
# 在專案資料夾下
npm run deploy
發佈完之後,當你用瀏覽器 Chrome 開啟台灣好天氣這個網站時,因為已經符合 PWA 的規範,所以會自動跳出提示來詢問使用者是否要安裝:
安裝後就會出現在應用程式列表中:
打開來就像一個原生的 App,但其實是包著 App 外皮的網頁:
是不是看起來很棒啊!
同樣的,讓我們來看看手機的畫面。當手機進入到這個頁面時,瀏覽器同樣會偵測到有符合 PWA 的規範,因此會跳出下載的按鈕或提示:
當我們把它安裝到手機後,它就像一般的手機 App 一樣,打開的時候會有一個漸變的啟動畫面,並且可以解除安裝:
終於完成 30 天這一系列鐵人賽的內容了,下面這些是我認為相當重要但故意先不告訴你的地方:
說真的這只是個開始,我希望的是這 30 天的內容能讓你對 React 有一個概念,接著你就可以閱讀 React 的官方文件;我希望你能夠越來越習慣閱讀官方文件,未來不論你想要換到哪一個框架或學習其他語言,千萬不要忘了回頭閱讀官方文件,那通常會是最清楚詳細的!
class
在定義組件在這 30 天中,我們都是使用函式來定義組件(Functional Components),因為 React Hooks 的功能讓我們可以把要做的事情都在 Functional Components 內完成;但在還沒有 React Hooks 前多數的組件都是用 class
定義的,因此若想看懂其他人寫的 React 程式碼,還是勢必要回頭補齊 Class-Components 的部分,這裡除了推薦 React 官方的 Getting Started之外,我認為 Codecademy 上也可以幫助你補齊這個部分。
如果你是在 React Hooks 之前就學過 React 的話,一定聽過「生命週期」這個東西,最常見的像是 componentDidMount
、componentDidUpdate
和 componentWillUnmount
,但在 React Hooks 之後,這些多能用 useEffect
替代,但生命週期的概念並不是不重要,而是如同第一天時所說的,有些時候過去學過的東西,反而會讓你學新事物的時候綁手綁腳,而現在是你可以在 React 的世界中自由探索學習的時候了!
這點說起來好像很容易,但平常我有在看手機版習慣,最常看到「從 iOS 跳到 Android」或從「Android 跳到 iOS」的使用者在抱怨:「為什麼我以為用 ooo 有這個功能,換過來 xxx 之後都沒有」。
可是多數時候,當你仔細去看使用者提出的問題後,會發現其實兩個系統都有相同或類似的功能,只是可能要在不同的地方才能找到。當你一直用原本的習慣想要去接觸新事物時,將會使得你窒礙難行,但若你可以用「新事物」的角度上網查一下,常常就會發現原來換過來後也有這個功能呀!好用!
上面這些話其實是在跟我自己說的,在學習的過程中,我常對於「能達到同樣功能但卻需要用不同方式」而感到厭煩。剛開始學網頁的時候,常會覺得 HTML, CSS, JavaScript 彼此三個不是活得好好的話,為什麼後來要出模板語言(Pug、Mustache、Handlebars、EJS)、為什麼後來要有 CSS 前處理器(SASS、SCSS、PostCSS)、為什麼要有前端框架,反正後來都還是編譯成 HTML, CSS 和 JavaScript 不是嗎?
在還沒有熟悉他們之前,的確會覺得「麻煩」,覺得「阿我就繼續用 ooo 就好了啊」!但實際上這些工具很多時候都是(當時)為了想要解決某些問題而生。想像過去的我若執著於功能都一樣,而繼續用原本單純的 HTML、CSS、JavaScript,那麼不只很難繼續進步,同時也無法體會到這些工具帶給我們的愉快感和成就感。
所以,不要害怕那些許許多多聽過、沒聽過的術語和詞彙,不懂的記下來,有需要找個時間再來弄懂它,就是這樣。不要被過去所認識的世界束縛你,一起共勉。
今天的程式碼同樣已經發佈到 Github 上,可以根據你的需求去檢視不同 Commit 階段的程式碼,Have Fun!
恭喜完賽!
剛開賽看到這個系列眼睛都亮起來,無奈也在趕賽,現在完賽,終於可以慢慢看這一系列了~
感謝帶來好文~
謝謝你~!!恭喜一起完賽!!
爬完30天,好文推推~~
覺得好感動!竟然有人爬完了!謝謝你,內容中應該還有一些地方有誤或不夠嚴謹,如果有發現的話再麻煩跟我說。
這個系列文真的好棒,讓我學到好多好多。
感謝你無私的分享大家如此實用的教學。^^
順便問一下,你的 VSCode 的左側有3個額外的 icons (下圖中紅色圈起來的部分),那些是什麼功能?要安裝什麼外掛嗎?
謝謝你的讓我知道對你有幫助!內容中應該還有一些地方有誤或不夠嚴謹,如果有發現的話再麻煩跟我說。
這三個套件分別是
這些不一定要安裝,可以看自己的需求,真的要推薦的話,我自己覺得這個抓錯字的最實用XDD
Code Spell Checker 可以參考看看
Po主的入门文很详细,每段程序前都把要点和逻辑罗列出来,看着很舒服.
跟着一直爬完了30篇,感谢.
非常感謝你爬完 30 篇文章,真心覺得這沒有比寫文章容易多少XDD
內容中如果有發現錯誤或不夠嚴謹的地方,再麻煩跟我說,謝謝。
爬完系列文了~感謝大大的分享,讓我對React Hook有更多瞭解~
不過最後的時候我有遇到一個問題,當我用iOS(13.3.1)瀏覽時,不管用Safari還是Chrome都會閃一下後變成白畫面,網頁或是app都會無法運作(我自己實作的或是你的都一樣)。
我有試著爬了一下文,但是沒有找到解決的方法,不曉得你知不知道是什麼問題?
終於看完了
也一樣做出一個天氣 APP
有幾個問題想問
<Context.Provider value={{ store, dispatch }}>
<Header />
<WeatherApp />
<Nav/>
</Context.Provider>
Header 點選某個按鈕後(靠 Reducer 傳遞 store 讓 Nav 接 ) Nav 會從左側滑出,會蓋住主畫面(WeatherApp)的一半
此時 Nav 滑出蓋住 WeatherApp 的時候,WeatherApp 會觸發 render console
在 WeatherApp 使用版主的 useRef 計數測試,確實是會增加的
這樣是合理的嗎??
supermrjiit 請問是否有像是 codesandbox 可以觀看呢?一般來說,看 WeatherApp 裡面是否也有拿 store 的資料,如果有的話,一旦資料有變動,WeatherApp 就會重新渲染
剛剛把公司網站的react 由16.4 升上17
這文章讓我獲益良多 感謝
另外想回報一下bug
day 25, 26... 的code sand box 出現問題了TypeError: Cannot read property 'dataTime' of undefined
有空可以去看看喔
https://codesandbox.io/s/weather-app-add-custom-hook-bvqdy
我大膽預測(?),應該是【日出日落】的資料沒有到2021年的~
我自己是又去氣象局下載新資料,再用筆者大大的程式過濾資料的。
vincentTang 非常謝謝你的回報!如同 evanyin 所說的,當初的資料並沒有抓取到 2021 年,codesandbox 的內容已經更新!也謝謝 evanyin 的回應!
今天做完文章內容上到github page了!
謝謝大大提供豐富的資料以及後續的修復方式。
不過我拿了兩支手機測試並沒有跳出下載按鈕(pixel6 & iphone6s+),應該是react沒有把serviceworker繼續當成default內容,API也更改了,翻了幾篇文章沒有找到解決方法,晚點忙完繼續找看看其他方式處理,再來更新留言。
再次謝謝大大提供這個系列文章!
沒錯喔!create react app 改版後的方式有些不同,可以再參考官網的說明,謝謝
https://create-react-app.dev/docs/making-a-progressive-web-app/
沒錯喔!create react app 改版後的方式有些不同,可以再參考官網的說明,謝謝
https://create-react-app.dev/docs/making-a-progressive-web-app/
我這陣子剛好也要做包含天氣的 APP,然後就看到這篇系列文了!
我想問一下,CWB 的 API 有沒有辦法拿到像是高雄市鳳山區這種的,我看了一下官方給的好像都只能到市/縣級