一樣開始前請記得在 local 端開好前端、後段:
後端:json-server --watch db.json --port 10000 --routes routes.json
前端:npm start
今天的文章就是要補昨天沒完成的洞─如何在網址列加上我們搜尋的關鍵字,
再拿這個關鍵字去 axios.get
。
為了要控制網址列跟取得網址列的參數,
首先我們要先安裝及 import react-router-dom
套件,
像這樣:
import {
BrowserRouter as Router,
Routes,
Route,
Link,
useLocation,
} from 'react-router-dom';
再來重點就是我們要在按下「搜尋」按鈕時,
一併把 ?q=
的參數也顯示在網址列當中,
昨天文章中搜尋列跟搜尋按鈕是這樣寫的:
<Flex w="50%">
<Input placeholder='請輸入要搜尋的關鍵字...' size='md' onChange={(e) => setSearchKeywords(e.target.value)} />
<Button colorScheme="blue" onClick={() => { searchDataKeywords(); }}>搜尋</Button>
</Flex>
今天我們改寫成這樣:
<Flex w="50%">
<Input placeholder='請輸入要搜尋的關鍵字...' size='md' onChange={(e) => setSearchKeywords(e.target.value)} />
<Router>
<Routes>
<Route element={<SearchButton keyWords={searchKeywords} />} path={'/'}></Route>
</Routes>
</Router>
</Flex>
主要是增加了 Router
的元素:
<Router>
<Routes>
<Route element={<SearchButton keyWords={searchKeywords} />} path={'/'}></Route>
</Routes>
</Router>
這段的意思是要建立路由 Router
,
一個路由通常會有很多路徑 Routes
,
在 Routes
我們將每一條 Route
定義好,
而各別的 Route
外觀會長怎樣,
就是由 element
決定,path
就是用來比對路徑,也就是說這個 Route
要在 /
才顯示,
如果是在別的連結,例如 /about
是不會顯示的,
像這樣,搜尋按鈕只出現在 /
的頁面, /about
沒有顯示:
那 element
裡面到底寫了什麼呢?
element={<SearchButton keyWords={searchKeywords} />
這邊拆解一下,我們宣告了一個 SearchButton
的 component,
然後可以想像的是裡面我們一定有宣告「搜尋」的按鈕,
像這樣:
const SearchButton = ({keyWords}) => {
return (
<div>
<Link to={`/?q=${keyWords}`}>
<Button onClick={() => {
setTimeout(() => {
setIsSearchOn(true);
}, 300)
}}>搜尋</Button>
</Link>
</div>
)
}
這邊要注意的是,在 <Button>
外面由 <Link>
包住,
意思是,當我按下 <Link>
裡面的元件後,網址前往 to={`/?q=${keyWords}`}
指向的連結,
(PS. keyWords
是由 <SearchButton keyWords={searchKeywords} />
傳入的,searchKeywords
就是我們在搜尋列所輸入的文字)
這邊我們試試看我們輸入文字並按下搜尋會出現怎樣的變化吧:
是的,你可以看到網址列已經出現 ?q=飯
的字眼了,
再來就是重頭戲,我們要如何拿到網址列的這個參數再進行後續處理。
首先我們要利用 react-router-dom
裡面的 useLocation
,
const location = useLocation();
console.log(location);
那我們一樣先用 console.log
來看一下 location
印出來的值:
你可以發現裡面有幾個值,其中 pathname
是代表現在在哪個路徑,search
是網址列帶的參數,
所以看起來 search
就是我們要拿來利用的。
再來這邊有點 tricky,我就稍微帶過去講一下。
本來我是這樣寫的:
const location = useLocation();
console.log(location);
const searchParam = location.search;
axios.get(`${hostUrl}/api/v1/sales${searchParam}`)
.then(function (response) {
setSales(response.data);
})
.catch(function (error) {
alert("抓取資料錯誤,請確認後再試");
console.log(error);
})
setIsSearchOn(false);
}
看起來很美好對吧,就是我們拿著 location.search
的值,
帶入到 axios.get
的 url 中,
應該就可以收工了?
但我在測試的時候發現,
按下搜尋的那個瞬間,
其實 url 還沒變成新的網址,
例如當我上一次輸入飯,這次輸入麵,
但你會發現你拿到的值還是"飯",而不是這次輸入的"麵",
所以我多宣告了一個變數 isSearchOn
const [isSearchOn, setIsSearchOn] = useState(false);
當我按下搜尋時,只是去控制這個 isSearchOn
的開關,
且故意延遲 setTimeout 後才去執行 setIsSearchOn
,
(避免太快去執行 axios.get
)
<Button onClick={() => {
setTimeout(() => {
setIsSearchOn(true);
}, 300)
}}>搜尋</Button>
當 isSearchOn
是 true
時,
才真的去 call API axios.get
,
call 完才把 isSearchOn
設為 false
,
所以這邊完整個程式碼是這樣的:
const SearchButton = ({keyWords}) => {
const location = useLocation();
console.log(location);
const searchParam = location.search;
if (isSearchOn){
axios.get(`${hostUrl}/api/v1/sales${searchParam}`)
.then(function (response) {
setSales(response.data);
})
.catch(function (error) {
alert("抓取資料錯誤,請確認後再試");
console.log(error);
})
setIsSearchOn(false);
}
return (
<div>
<Link to={`/?q=${keyWords}`}>
<Button onClick={() => {
setTimeout(() => {
setIsSearchOn(true);
}, 300)
}}>搜尋</Button>
</Link>
</div>
)
}
那我們一樣來看看效果如何吧:
把昨天的債還掉了,
那明天文章再見囉!
React 中優雅使用網址參數 Query String
React Router
新版 React router 怎麼用? React-router-dom v6!
React Router 與 Hook 的邂逅
Day 19-你好,React Router 4(安裝及角色介紹)
(↑偶然找到有大大在鐵人賽講到 React Router 的文章,而且剛好跟我一樣是第19天,也太巧XD)
REMIX / REACT ROUTER
(↑不過這好像是 V5 的寫法,<Switch>
的寫法在 V6 已經不適用的樣子)
終於寫出來了orz
其實用 Next.js
提供的 next/router
,
應該可以更快寫完,但一直卡關,
所以只好拿 React Router
來寫了,
然後因為從來沒用過 React Router
,
所以也是試滿久的,
查了查發現 React Router
好像有大改版過,
所以大大們的寫法都不太一樣,
試了一陣子才找到可以 work 的寫法orz
因此如果我有錯誤之處請大大們不吝鞭策與指教(跪)
每天都離天窗更近了QQ