一樣開始前請記得在 local 端開好前端、後段:
後端:json-server --watch db.json --port 10000 --routes routes.json
前端:npm start
這幾天的範例都圍繞在餐廳,
我們現在也知道 axios
的 CRUD 該怎麼做了,
所以是時候來做一個簡易後台了吧?
(就是讓使用者可以在表單自行輸入後,前台就會出現新增的資料)
先初步想一下我們可能會需要哪些元件跟功能:
好,那我們大概可以下手了,
首先先從"切換前後台"開始,還記得昨天介紹的 React Router 嗎?
那我們先把主要的架構寫出來,
像這樣:
<Flex justifyContent="center">
<Router>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/admin" element={<AdminPage />} />
</Routes>
</Router>
</Flex>
這邊簡單說明一下,這邊設定了兩條路徑,
一個在 /
,另一個在 admin
,
也就是首頁 <Home />
跟 後台頁面 <AdminPage />
,
因此我們在 element 各別這樣設定之後,
我們就要來宣告首頁要顯示什麼,後台頁面要顯示什麼。
const Home = () => {
return (
<div>
<Button m={2} onClick={fetchData}>全部資料</Button>
<Button m={2} onClick={searchData} colorScheme="teal">人氣料理</Button>
<Link to={`/admin`}>
<Button m={2} colorScheme="twitter">後台管理</Button>
</Link>
<OrderedList px={4}>
{sales?.map((x) => (
<ListItem my={2}>
<Flex>
<Text>{x.item}</Text>
{x.count >= hitCount ? (
<Tag ml={2} size="sm" variant="solid" colorScheme="red">
人氣料理
</Tag>
) : null}
</Flex>
<Text>銷售量:{x.count}</Text>
</ListItem>
))}
</OrderedList>
</div>
)
}
這邊幾乎就是把之前寫的 code 搬進去 <Home>
裡面,
只是今天我們多了後台管理頁面,
所以加了一個會導向 /admin
的按鈕,
像這樣:
<Link to={`/admin`}>
<Button m={2} colorScheme="twitter">後台管理</Button>
</Link>
再來就是我們要設定後台管理頁面要顯示什麼,
這邊先不把表單寫進來,
我們先測試前後台切換O不OK就好,
因此後台也要新增一個回前台的按鈕,
像這樣:
const AdminPage = () => {
return (
<div>
<Link to={`/`}>
<Button colorScheme="blue">回前台</Button>
</Link>
<Text my={4} as="h2" fontSize="2xl" textAlign="center">
{today.getFullYear()} 鐵人餐廳 - 後台管理
</Text>
</div>
)
}
那我們先來看一下效果:
看起來前後台頁面切換沒問題了,
那我們就來搞定後台的表單吧。
還記得之前我們在做搜尋功能時,
我們是用 <Input>
的元件,
然後再設定 onChange
時把文字框輸入的值用 useState
存下來,
像這樣:
<Input placeholder='請輸入要搜尋的關鍵字...' size='md' onChange={(e) => setSearchKeywords(e.target.value)} />
但這樣不就代表我有幾個欄位就要宣告幾個 useState
設定 onChange
幾次?
這樣會不會太麻煩了?
因此這邊就要介紹 react-hook-form
的 useForm hook,
它可以讓你直接在表單上註冊該欄位,
然後就可以直接取得值,
那我們直接試試看吧!
首先一樣先安裝 react-hook-form
跟 import useForm,
像這樣:
import { useForm } from "react-hook-form";
再來我們要在主程式的地方宣告這些:
export default function Home() {
const { register, handleSubmit, reset } = useForm();
const submit = data => console.log(data);
... (略)
再來就是回到後台頁面的地方,
我們要把 form
表單給放進去,
像這樣:
const AdminPage = () => {
return (
<div>
<Link to={`/`}>
<Button colorScheme="blue">回前台</Button>
</Link>
<Text my={4} as="h2" fontSize="2xl" textAlign="center">
{today.getFullYear()} 鐵人餐廳 - 後台管理
</Text>
<form onSubmit={handleSubmit(submit)}>
<FormLabel my={4}>品項</FormLabel>
<Input placeholder='請輸入品項' type="text" {...register("item", { required: true })} />
<FormLabel my={4}>數量</FormLabel>
<Input placeholder='請輸入數量' type="number" {...register("count", { required: true })} />
<Button my={4} type="submit">送出</Button>
</form>
</div>
)
}
先看一下現在介面是什麼樣子:
這邊解釋一下關鍵的地方,
第一個 <Input>
裡有寫 {...register("item")}
這是代表這個文字框被註冊成 item
這個欄位,
以此類推,第二的 <Input>
裡有寫 {...register("count")}
就是這個文字框被註冊成 count
的欄位。
回到 <form>
的設定,<form onSubmit={handleSubmit(submit)}>
的意思就是說當表單被送出時,會去執行 handleSubmit(submit)
submit 這個 function 就是稍早我們有設定的 const submit = data => console.log(data);
地方,
那我們來試一下我們現在輸入表單並送出會發生什麼事吧!
神奇的事發生了,
它會自動把剛剛輸入的內容包裝成 JSON 格式的樣子並回傳:
{
"item": "ABC",
"count": "123"
}
所以拿到資料之後,
我們就可以很順利的 call axios.post
了對吧,
那當然我們就是要寫在 submit
的 function 之中,
像這樣:
const submit = data => {
console.log(data);
axios.post(`${hostUrl}/api/v1/sales`, data)
.then(res => {
console.log(res.data);
});
}
這邊你可以發現 data
可以直接代入到 axios.post
第二個參數之中,
不需要再經過處理。
那我們整個來試試看效果如何吧!
看起來我們成功把前後台串起來了!!!!!
然後還有個小小的地方,
就是你可能發現表單送出後不會清空,
這邊 useForm
也有提供 reset
(清空表單) 的功能,
那我們把它加入之後再整個試一次吧!
const submit = data => {
console.log(data);
axios.post(`${hostUrl}/api/v1/sales`, data)
.then(res => {
console.log(res.data);
reset();
});
}
看起來這個簡易後台都OK了!
總結一下,今天我們用了 React Router
串前後台頁面,
再用 useForm
搭配 axios.post
寫出簡易後台進行資料的新增。
用今天這篇文章為這個階段做個小小收尾,
這個階段我們知道如何去 call API 進行資料的 CRUD。
那接下來就要進入下一階段了,
明天的文章再見囉!
終於來到第20天,
最後10天,加油~~~