前幾天講了 axios 的 CRUD,
還有昨天講了 routes,
今天回過頭來講 filter 吧。
相信大家對網址列含有 ?
及 &
的符號並不陌生,
像是鐵人賽的個人頁面網址就長這樣:https://ithelp.ithome.com.tw/users/20129873/ironman/5274?page=1
?page=1
其實就是前端 call API 時給它的 filter
哦,?page=1
就代表前端只要求 API 回傳第1頁的資料就好,
以此類推,如果只要第2頁的資料,那麼我們參數就改成 ?page=2
,
那我們簡單試試看吧!
當然通常使用者不會自己去改瀏覽器網址列的參數,
而是透過使用者行為(EX. 輸入文字框、按下按鈕...)之後,
去改變前端 call API 的參數,
讓回傳的資料有所改變。
例如這邊我們簡單寫一個例子,
增加一個按鈕:
<Button mx={2} onClick={searchData} colorScheme="teal">搜尋資料</Button>
然後在 searchData
我們這樣寫:
function searchData(){
axios.get(`${hostUrl}/api/v1/posts?author=Misado`)
.then(function (response) {
setdataResult(response.data);
setDataFetchTimes(dataFetchTimes+1);
})
.catch(function (error) {
alert("抓取資料錯誤,請確認後再試");
console.log(error);
})
}
重點就是我們在原本 url /api/v1/posts
的地方,
後面加了 filter 條件 ?author=Misado
,
那我們來試試看效果:
原本有7筆資料,
但按下搜尋資料的按鈕之後,
就只回傳 author=Misado
的2筆資料。
那如果現在我有多個條件呢?
例如現在我再多個條件只要拿編號為7,
該怎麼寫?
那就用 &
符號將兩個串接就好,
像這樣:
axios.get(`${hostUrl}/api/v1/posts?author=Misado&id=7`)
現在同時符合兩個條件的只有一筆資料:
你也可以先在瀏覽器輸入 http://localhost:10000/api/v1/posts?author=Misado&id=7
其實你會發現結果是一樣的,
所以通常在寫 filter
時,
我會自己先在瀏覽器的網址試試看,
確定這是我要的 filter
條件,
才把它正式寫到 function 去。
(PS. API 通常會寫 filter
但不一定都會寫,
這次我們自己起的 JSON Server 是都有支援,
但如果你發現前端想下的條件 API 並沒有吐相對的資料給前端的話,
可能就是 API 沒有寫這樣的邏輯,
這時候前端就要跟後端講說請把這個條件加進去)
但如果今天的文章這樣就結束了好像有點無聊,
還記得之前的鐵人餐廳例子嗎?
之前我們是寫死資料,
但現在我們終於有 API 了,
所以就來改寫看看吧!
首先我們在 db.json
新增這樣的資料:
"sales": [
{
"item": "牛肉麵",
"count": 66
},
{
"item": "小籠包",
"count": 55
},
{
"item": "滷肉飯",
"count": 30
},
{
"item": "蚵仔麵線",
"count": 25
},
{
"item": "蚵仔煎",
"count": 20
}
]
(PS. 這邊讓我先把原本的 品項
跟 數量
改成英文的 item
跟 count
,
不然 url 會有中文編碼的問題,
那又是另外一件事了XD 有機會再說明~)
再來我們一樣先在瀏覽器試試看:
http://localhost:10000/api/v1/sales
確定 API 能夠正常回傳資料後我們就來進行改寫,
const [sales, setSales] = useState([]);
... (略)
function fetchData(){
axios.get(`${hostUrl}/api/v1/sales`)
.then(function (response) {
console.log(response);
setSales(response.data);
})
.catch(function (error) {
alert("抓取資料錯誤,請確認後再試");
console.log(error);
})
}
然後把第6天寫的前端 code 貼過來,
在 sales.map
的地方加個 ?
,
避免沒有資料就渲染導致錯誤,
像這樣:
https://codesandbox.io/s/2022day6-chakra-ui-k9eohm?file=/src/App.jsx:206-254
<Text my={4} as="h2" fontSize="2xl" textAlign="center">
{today.getFullYear()} 鐵人餐廳 {today.getMonth() + 1}月 銷售排行 TOP5
</Text>
<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>
然後來看看效果如何:
然後一樣複習一下剛剛介紹的 filter,
如果現在我們只想看銷售量(count)大於 hitCount
的資料該怎麼做呢?
JSON Server 還有提供 _gte
_lte
的運算子(Operators),
所以當我們在瀏覽器這樣下 http://localhost:10000/api/v1/sales?count_gte=50
就可以取得 count
大於等於 50 的資料,
像這樣:
所以現在我們一樣來新增一個人氣料理的按鈕,
按下去執行 searchData,
裡面會 call axios.get
url 我們就這樣寫:
function searchData(){
... (略)
axios.get(`${hostUrl}/api/v1/sales?count_gte=${hitCount}`)
.then(function (response) {
setSales(response.data);
})
.catch(function (error) {
alert("抓取資料錯誤,請確認後再試");
console.log(error);
})
}
... (略)
<Button m={2} onClick={searchData} colorScheme="teal">人氣料理</Button>
那我們一樣來看看執行結果:
今天介紹了 filter ?
跟 &
的寫法,
這也是前端 call API 時常用到的語法,
當然前端也可以自己在語法將 API 回傳回來的資料再進行過濾就好,
不過在資料量多的時候這樣對頁面的 loading 其實很大,
例如全部有10,000筆資料,
但你想要的其實只有其中的50筆,
這時候 API 只回傳 50 筆給前端是最好的,
不然拿到10,000筆甚至更多,
會產生不必要的 loading。
那我們一樣明天再見啦~
一邊趕鐵人賽文章遇到地震!
而且這次搖滿大的QQ
剛才好像又有第二次orz
希望大家平安無事QQ