React
GitHub
本篇為 [FE302] React 基礎 - hooks 版本 這門課程的學習筆記。如有錯誤歡迎指正!
在開始之前,可先整理 React 專案的資料結構, 例如將 src 路徑下的檔案分成 components 和 constants 兩類:
Todo 是備份我們前面做的 TodoList 範例,MessageBoard 則是本篇要實作的內容。
這裡有個小技巧,之所以在 APP 資料夾底下還有個 index.js,是為了在 src 根目錄底下的 index.js 可以用 ./component/App
直接引入,而不需寫成 ./component/App/App
,藉此簡化資料結構:
但這樣其實有個壞處,只看檔名會不知道其功能,必須搭配所在資料夾。因此會改成由 App 資料夾底下的 index.js 引入 App.js 再匯出:
因此實際上還是在撰寫 App.js 這個檔案,這是實際工作中常用的小技巧:
結果如下,能夠正常 render 出 App:
完成前置作業之後,接著就可以開始實作留言板了!
同樣引入 styled-components 來寫 CSS:
先思考頁面上需要哪些功能,切出相對應的 Component 架構:
再透過 styled-components 來修改樣式:
結果如下:
刻好介面以後,再來就可以串接 API 讀取資料啦!
測試用的 API 可參考:Lidemy 學生專用 API Server,留言板要串接的是 Comments API,資料結構如下:
URL:https://student-json-api.lidemy.me/comments
引入 useState 使用,設定 component 初始狀態:
當我們要對 Component 做一些事情時,通常會有兩種方式:
而我們的目標是「在 render 之後拿取資料」,因此在這裡選用 useEffect:
接著寫 useEffect 在 component mount 之後要做的事情,透過 fetch 來拿取 API 的資料,轉成 JSON 格式後,再以 setMessages 改變狀態,也可用 catch 進行錯誤處理:
並在 component 加上與傳入參數相對應的屬性,List 結構的資料會用 map() 方式拿取,用 id 當 key:
接著微調 MessageContainer styled,每則留言會跟上一則有距離,有兩種寫法:
串接 API 結果如下:
實作一個 ErrorMessage Component 來顯示錯誤訊息:
例如修改 API_ENDPOINT 網址,多加其他參數:
畫面就會顯示錯誤訊息:
當沒有留言,也就是 messages.length === 0
時才會出現:
結果如下:
但這種寫法其實會有個問題,也就是重新 render 的一瞬間會先看到 No Message,然後才是讀取到的 API 資料。
可在判斷加上 messages &&
,必須確認裡面有東西(是一個陣列)才會執行:
根據終端機顯示的警告訊息,幫 Component 加上 PropTypes:
引入 prop-types 套件:
Message Component:
會發現 time 格式有誤:
可透過 JavaScript 的 new Date 轉成一個 Object,再用 toLocaleString() 這個方法,根據瀏覽器的語言轉換成我們看得懂的格式:
這樣寫的好處就是不需另外引入 Library!
接著修改程式碼,轉換 message.createdAt
的格式:
這樣就成功轉換時間格式:
在表單中,textarea 或 input 就屬於受控組件,而受不受控的組件比較如下:
在表單中的 MessageTextArea 屬於 Controled Component,需透過 useState 來改變狀態,可設定 onChange 綁定事件機制,根據輸入的 value 來 setValue:
這時按下送出鍵時,頁面會重新整理,這是預設的送出表單行為。因此我們要在 Form 加上 onSubmit 事件機制,以 e.preventDefault() 阻止預設行為,再執行我們想要的事情:
使用API 文件 提供的方法來新增資料:
但如果在 textarea 為空時送出 submit,會顯示下方錯誤訊息:
因此可在顯示訊息前可進行錯誤處理,根據是否 ok 顯示錯誤 data.message
:
再根據有無 postMessageError 決定是否顯示:
但其實在送出新的留言之前,也就是當使用者 focus 在 textarea 區塊時,就可以取消錯誤訊息,可透過 onFocus 事件處理:
這樣在 focus textarea 時,錯誤訊息就會消失。
但是還有個問題,就是即使表單為空時還是可以不斷送出 request:
可透過判斷「是否能送出留言的 state」解決這個問題:
或是建立一個 Loading Component 並 render 在畫面上,這樣 button 就不會被點擊:
結果如下:
可以透過開發者工具 -> 選擇 Slow 3G 降低網速,以觀察 Loading 的狀況:
或是選擇 Add… 來自己新增一個 super slow 網速,把下載速度設為 1 kb/s:
在之前實戰 TodoList 中有提到,刪除功能會用 filter() 處理:
在留言板也是相同道理,只是再加上串接 API 的步驟!
若要在 component 加上事件機制,可將 function 作為參數從父層傳到子層,步驟如下:
並傳入參數給 Children,這裡指的就是 handleDeleteMessage
這裡要傳入 message.id
表示選中的 id:
DELETE method 不用傳入 request body,fetch 後直接用 .then 接續後面的動作,也就是以 setMessages 改變 component 狀態:
結果如下:
參考資料:
詳細步驟可參考官方文件:https://create-react-app.dev/docs/deployment/
在部署之前,可透過 npm run build 指令來優化專案程式碼,像是進行 bundle、去除空格等:
build 完成後如下方畫面,可跟著下方步驟在本地端架 server:
輸入下方指令,會在本地端建立一個 HTTP server,可在 http://localhost:5000/
預覽畫面:
並且會在 React 專案建立 build 資料夾,存放 HTML、JS 等檔案:
可參考官方文件:https://create-react-app.dev/docs/deployment/#github-pages
結果如下:
把下方內容改成自己的專案網址:
輸入下方指令即可完成部署:
點選專案的 Setting 頁面:
往下拉可以查看 GitHub Page 的網址:
其實在實作留言板之後,會發現思考方式和 Todolist 很類似,只是多了串接 API 的步驟來拿取資料,此外像是資料結構、建立 Component、透過事件機制或改變狀態來 render 畫面等等。
或許是因為,之前是一邊實作一邊聽講解的關係,觀念會比較零散一點,但這次又再從頭實做一個小專案,瞭解到該如何整理專案結構,根據想要的頁面功能似去建立 Component,熟悉 styled-components 的寫法。
Huli 在這章節最後說可以挑戰看看分頁和刪除功能,自己就另外去找資料來挑戰看看,刪除功能的話,感覺之前在其他工具也有講到類似觀念,實作起來應該不會太難…?(馬上立 Flag),雖然花了一點時間去 debug,但也總算被自己試成功了!獲得小小的成就感,之後也想找時間來試試看分頁功能,總之先繼續前進部落格實作吧!