---
tags: React.js
---
# React Hook Form & React Context
## React Hook Form 使用教學
這是一個表單套件
可以直接進入[官網](https://react-hook-form.com/form-builder)設定好需要的表單欄位與驗證內容
送出後右邊就會自動產出程式碼給你複製使用
範例:
```jsx=
function App() {
const {
register, // 註冊表單欄位
handleSubmit, // 處理提交事件
formState: { errors } // 處理錯誤狀態
} = ReactHookForm.useForm();
const onSubmit = (data) => alert(JSON.stringify(data));
console.log(errors); // data 是 object 裡面放 { inputName: inputValue }
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input
type="text"
placeholder="First name"
{...register("First name", { required: true, min: 3, maxLength: 80 })} // 這裡是註冊語法 (inputName, {輸入框條件})
/>
<input type="submit" />
</form>
);
}
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<App />);
```
## React Hook Form 錯誤提示作法
### 一、沒填寫或格式錯誤統一顯示某段文字
```jsx=
<form onSubmit={handleSubmit(onSubmit)}>
<div>
帳號:
<input placeholder="帳號" name="account" {...register("account", { required: true })} />
{errors.account && <span>錯誤訊息內容</span>}
</div>
<div>
密碼:
<input
name="password" type="password" placeholder="密碼"
{...register("password", { required: true })}
/>
{errors.password && <span>錯誤訊息內容</span>}
</div>
<input type="submit" />
</form>
```
針對 `{errors.account && <span>錯誤訊息內容</span>}` 說明:
&& 是邏輯運算子,規則是
```htmlmixed=
當左邊可解析成 false 就會回傳左邊的東西
當左邊可解析成 true 就會直接回傳右邊的東西
當左右兩邊都是 True 時才會回傳 True,否則回傳 false
```
所以當 errors.account 有內容,就會回傳右邊的 `<span>錯誤訊息內容</span>`
### 二、根據不同狀況提示不同錯誤
```jsx=
<input
type="email"
placeholder="email"
{...register("email", {
required: { value: true, message: "此欄位必填寫" },
pattern: {
value: /^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/g,
message: "不符合 Email 規則"
}
})}
/>
{errors.email?.message}
```
當 required 為 true 但沒有填寫,`{errors.email?.message}` 就會是 `"此欄位必填寫"`
當有填寫但格式錯誤,`{errors.email?.message}` 就會是 `"不符合 Email 規則"`
## Context
概念上類似 windows 的全域變數
在最外層建立的東西可以被其他區域查找並使用
範例:
```jsx=
const MyContext = React.createContext(); // 建立全域環境
function ThemeText() {
const theme = React.useContext(MyContext); // 抓取環境傳入的變數
return (
<p style={{ color: theme.background }}>
我是 theme 中的 light background 色的文字
</p>
);
}
function App() {
const themes = {
light: {
foreground: "#ffffff",
background: "#313675"
}
};
return (
// 屬性 value 傳入要共享的資料,MyContext.Provider 裡面包元件
<MyContext.Provider value={themes.light}>
<ThemeText />
</MyContext.Provider>
);
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
```
### 把 useContext 整成一個 import 的檔案
基本用法就是先建立一個環境 => const AuthContext = createContext()
接著在要用到的地方抓取這個環境 => useContext(AuthContext)
所以根據 import/export 的方式可以獨立拆成一個檔案 `Context.js`,
檔案內容如下:
```jsx=
import { createContext, useContext } from "react";
export const AuthContext = createContext(null); // 匯出 AuthContext 這個參數 => 等同於上一段範例中的 const MyContext = React.createContext();
export const useAuth = () => { // 匯出 useAuth 這個函數 => 等同於上一段範例中的 const theme = React.useContext(MyContext);
return useContext(AuthContext);
};
```
建立好 Context.js 後,最主要的 App.js 就可以用 `AuthContext.Provider` 標籤
通過屬性 value ,傳入共用資料 { token, setToken }
讓 `AuthContext.Provider` 標籤包裹著的元件們都可以使用這個共用資料了
如下:
```jsx=
function App() {
const [token, setToken] = useState(null);
return (
<div className="App">
<AuthContext.Provider value={{ token, setToken }}>
<Routes>
<Route path="signUp" element={<SignUp />} />
<Route path="Login" element={<Login />} />
</Routes>
</AuthContext.Provider>
</div>
);
}
```
> 說明一下 `<AuthContext.Provider value={{ token, setToken }}>`
> 因為 React 可以省去雙引號通過 xxx={xxx} 傳東西
> 剛好要傳進去的又是物件 { token, setToken }
> 所以 value={共用資料} 就變成 value={{ token, setToken }}
> 實際傳入的還是物件 { token, setToken } 不是 {{ token, setToken }} 哦!
元件檔案想使用共用資料時,
在元件檔案最開頭 `import { useAuth } from "./Context";`
接著通過 `const { token, setToken } = useAuth()` => 物件解構方式
就可以像正常 useState() 一樣讀取 token、通過 setToken 設定 token 囉