# 第五週 本頁連結:https://hackmd.io/5foB4HVoT9GKTwvaJBkdKQ ## 完課獎勵說明 完整獎勵說明:https://hackmd.io/ry4GF6KWROKbx9cLf51bkA - 2/16 前 50%:超過 100 人挑戰成功,全班直播加碼授權一年 - 前完成課程報到 -> 第四週主線 - 2/23 前 60%:框架菁英班直播 → 主題:Next.js 起步走 - 完成課程報到 -> 第六週主線 或 第五週主線 + 心得牆 - 3/9 前 80%:框架菁英班錄影(目前以 Vue 為主,React 可參考主題包含:從零建構 API、Cloud flare、前端工程師如何寫出好履歷) - 完成課程報到 -> 第七週主線 或 第六週主線 + 心得牆 - 100%:數位完賽獎狀 ## 提醒:作業繳交說明 - 所有繳交期限 3/23 - **最終延長繳交條件**:3/23 前完整繳交(沒有被直接退件),可延長批改至 4/13 - 直接退件的原因: - 助教下載後,`npm run dev` 無法運行 - 作品不完整(作品內容有缺、有大量假字) ### 本週重點 - Hook - 自定義 Hook - 使用外部 Hooks:https://github.com/streamich/react-use - React Hook Form - React 開發優化: - 局部 Loading - 全畫面 Loading - Loading State 管理 - https://www.npmjs.com/package/react-loading - https://www.npmjs.com/package/react-spinners - useContext → 可自行看影音課程,後續會跳 redux toolkit ## 關於 Hooks ### 1. Hook 的概念 > Hooks 實現細粒度的邏輯拆分,讓功能更小、更純粹,元件僅將需要的功能引入,或者將重複的邏輯進行封裝。 > 可以參考[課程教學](https://courses.hexschool.com/courses/react-video-course1/lectures/53655925),簡單概念如下: 1. 先撰寫一份可運作的程式碼 2. 可嘗試將相關的邏輯抽出,定義成 use… 作為獨立 hook 3. 嘗試匯入運行,確認無誤後,可建立成獨立檔案 > 剛開始,可以放到 hooks 資料夾內,並使用 use….js 命名即可 ### 使用現成的 Hooks 參考:https://github.com/streamich/react-use 範例: 1. useMouse 2. *useDropArea* 3. useDebounce ## React Hook Form ### 基本表單知識 常見表單標籤 - form - label - input - button ### React Hook Form #### 基本表單觀念 1. form 、 action 、submit 2. button 3. label 與 input #### React 常見表單問題 0. 基礎表單輸入 1. checbox 單選與複選 2. select 預設值 3. 混合(炸) #### 為什麼要使用 React Hook Form 1. 因為原有的 React 開發表單相對困難很多:參考 - https://courses.hexschool.com/courses/react-video-course1/lectures/53655949 2. 包含錯誤回饋的部分 ### 使用 React Hook Form **基礎使用** 1. 安裝 React Hook Form:npm install react-hook-form 2. 初始化 React Hook Form ```jsx import { useForm } from "react-hook-form" function Component() { const { register, // 用來註冊表單元素 handleSubmit // 用來處理表單提交 } = useForm(); const onSubmit = (data) => { // 表單送出實際的資料內容 console.log(data); }; return () } ``` 1. 將表單元素套用至 input 上 ```jsx= <form onSubmit={handleSubmit(onSubmit)}> <input {...register("firstName")} /> <input {...register("lastName")} /> <button type="submit">送出</button> </form> ``` - 預設值定義方式 ```jsx const { register, handleSubmit } = useForm({ // 使用參數 defaultValues defaultValues: { firstName: "John", lastName: "Doe" } }) ``` - 各類表單元素套用方式 ```jsx {/* 各種表單元素,基本套用方式 */} <input {...register("email")} /> <select {...register("category")}> <option value="">Select...</option> <option value="option1">Option 1</option> <option value="option2">Option 2</option> </select> {/* 單選 Checkbox */} <input type="checkbox" {...register("isChecked")} /> Checkbox {/* 多選 Checkbox */} <label> <input type="checkbox" {...register("like")} value="鍋燒意麵" /> Option 1 </label> <label> <input type="checkbox" {...register("like")} value="炒麵" /> Option 2 </label> <label> <input type="checkbox" {...register("like")} value="漢堡" /> Option 3 </label> {/* 單選 Radio */} <input type="radio" {...register('gender')} value="男" /> 男 <input type="radio" {...register('gender')} value="女" /> 女 ``` **監聽當前行為** 影音課程中有兩種方法:https://courses.hexschool.com/courses/react-video-course1/lectures/53655956) 1. 取出 Watch 行為 ``` import { useForm, useWatch } from "react-hook-form" ``` 2. 取出 Control ```jsx const { register, handleSubmit, control, // 判斷控制的表單 } = useForm({ ... }); ``` 3. 將值取出,並呈現在畫面上 ```jsx const watchForm = useWatch({ control, }); useEffect(() => { console.log(watchForm); }, [watchForm]); ``` **驗證方法(基礎)** 1. 驗證 required (必填,如果沒有填寫則無法送出 ```jsx <input type="text" { ...register('username', { required: true, }) } /> ``` 2. 錯誤回饋,取出 erros ```jsx const { register, // 用來註冊表單元素 handleSubmit, // 用來處理表單提交 control, // 判斷控制的表單 formState: { errors }, // 錯誤訊息 } = useForm({ ... }); console.log(errors); // 當有錯誤時,這裡會出現資訊 ``` 3. 將錯誤呈現在畫面上 ```jsx <span>錯誤訊息:{ errors.username ? '這個欄位為必填' : '' }</span> ``` 4. 可選:是否要立即做判斷 ```jsx const { ... } = useForm({ ... mode: 'onChange', // 表單驗證的時機 }); ``` **驗證方法:進階** 常見驗證技巧 參考資源:https://react-hook-form.com/docs/useform/register ```jsx <input type="password" {...register("password", { required: "密碼是必填項目", minLength: { value: 6, message: "密碼長度至少需為 6 個字元", }, maxLength: { value: 12, message: "密碼長度不得超過 12 個字元", }, })} /> <span> {errors.password ? errors.password.message : ""} </span> <br /> <input type="email" {...register("email", { required: "Email 是必填項目", pattern: { value: /^[^\s@]+@[^\s@]+\.[^\s@]+$/, message: "請輸入有效的 Email 格式", }, })} /> <span> {errors.email ? errors.email.message : ""} </span> <br /> <input type="text" { ...register('phone', { required: '請填寫手機號碼', pattern: { value: /^[0-9]{10}$/, message: '手機號碼格式錯誤', }, }) } /> <span>錯誤訊息:{ errors.phone ? errors.phone.message : '' }</span> ``` - 正規表達式可搭配 AI 使用 (前後補上 `/`) ![image](https://hackmd.io/_uploads/H12UZneu1x.png) ### 錯誤樣式 ``` className={ `${errors['email'] ? 'error-state' : ''}` } ``` ## Loading 效果開發 - 全畫面 Loading - 可搭配:https://www.npmjs.com/package/react-spinners - https://www.npmjs.com/package/react-loading - 單一元素 Loading - 可搭配:https://getbootstrap.com/docs/5.3/components/spinners/ - 列表單一元素 Loading ## 本週額外挑戰 - 預習章節閱讀:[連結](https://rpg.hexschool.com/#/training/12062543649513962870/board/content/12062543649513962883_12062543649513962890) - 環境建置(完整看完) - Router - 作業連結:https://rpg.hexschool.com/#/training/12062543649513962870/board/content/12062543649513962871_12062543649513962892?tid=12062543649528478358 - 助教作業解說(週日上午 10:00) ![image](https://hackmd.io/_uploads/BkXeKpsSke.png) - 團隊任務: - https://rpg.hexschool.com/#/training/12062543649513962870/board/content/12062543649513962879_12062543649513962909