要讓系統活起來,當然要能寫入資料!今天我們要實作一個不會跳轉頁面的彈出對話框 (MUI Dialog),裡面包含一個表單,讓使用者輸入捕獲的寶可夢資訊 (性別、是否為亮晶晶等),並準備好呼叫 POST API。
在 React 中處理表單輸入,我們有兩種寫法可以選擇:
| 控制方式 | 運作原理 | 優缺點與適用情境 |
|---|---|---|
| 受控組件 (Controlled) | 把 Input 的值綁定在 useState 上。每次打字都會觸發重新渲染。 |
優點:可以做到「即時字數統計」、「即時驗證輸入格式」。缺點:如果表單超大,打字可能會卡頓。適用:絕大多數的 React 表單 (本專案採用)。 |
| 非受控組件 (Uncontrolled) | 使用 useRef。打字時不觸發渲染,直到按下送出按鈕時,才一口氣把值抓出來。 |
優點:效能極高。缺點:無法做即時的連動邏輯。適用:超大型問卷表單。 |
我們使用 MUI 的 Dialog 組件搭配受控組件 (useState) 來製作表單:
import { Dialog, DialogTitle, DialogContent, DialogActions, TextField, Button, Switch, FormControlLabel } from '@mui/material';
import { useState } from 'react';
const AddHoldingDialog = ({ open, onClose }) => {
// 受控組件:將狀態綁定在 State 上
const [notes, setNotes] = useState('');
const [isLucky, setIsLucky] = useState(false);
const handleSubmit = () => {
// 這裡會去呼叫 API: api.post('/holdings', { notes, isLucky... })
// 送出後關閉視窗
onClose();
};
return (
<Dialog open={open} onClose={onClose} fullWidth maxWidth="sm">
<DialogTitle>新增寶可夢紀錄</DialogTitle>
<DialogContent sx={{ display: 'flex', flexDirection: 'column', gap: 2, pt: 2 }}>
{/* Switch 開關 */}
<FormControlLabel
control={<Switch checked={isLucky} onChange={(e) => setIsLucky(e.target.checked)} />}
label="是否為亮晶晶?"
/>
{/* 多行輸入文字方塊 */}
<TextField
label="備註"
multiline
rows={3}
value={notes}
onChange={(e) => setNotes(e.target.value)}
/>
</DialogContent>
<DialogActions>
<Button onClick={onClose} color="inherit">取消</Button>
<Button onClick={handleSubmit} variant="contained">確認新增</Button>
</DialogActions>
</Dialog>
);
};

新增寶可夢視窗,透過實際的 UI 元素讓使用者自行設定(下拉選單、Switch 開關、按鈕等)。
有了這個表單,朋友終於可以自己輸入熱騰騰剛抓到的寶可夢了!還記得我們在 DAY 13 實作了上傳標籤圖示的後端嗎?明天,我們要用 FormData 把圖片從前端送過去!