第二十二課:Context Api串接至component實作與介紹part2
github Day21~23完成的連結
前一天我們了解了contextApi在react中的概念,並創建了第一個contextApi component,而今天將會注重在跳脫contextApi.js,將它串接到我們的login與其他component上,注重在外部創接的實作。
首先要讓能整個context提供他的暫存器給我們的app,我們要延續昨天的provider,把它包裹著我們的app.js,所以每當我們新設立好一個context就需要去到index.js應用provider包裹。
包裹完後回到我們的loginPage,我們要將登入資料上傳至contextApi,跟註冊一樣我們會先完成input的資料儲存與登入按鈕的handleClick等等函數,這邊要特別注意我們login的body,在login api設置時,將帳號設為account而不是username,因為我們希望他可以不管事username還是email都可以登入,如下
串接contextApi的準備
const registerSuccess =useLocation()
//接我們register navgate過來的res
const{loading, error, dispatch}=useContext(LoginContext)
const [loginData, setLoginData] = useState({
account:undefined,
//設置Api的時候是設置account 所以要注意不要打成username了
//當初這樣設計是因為我們想要讓他就算是輸入username與email都可以登入
password: undefined
})
const handleChange=(e)=>{
setLoginData(prev=>({...prev,[e.target.id]: e.target.value}))
}
input的設置都跟register一樣
<input type="text" id="account" placeholder='帳號' onChange={handleChange} />
<input type="password" id="password" placeholder='密碼'onChange={handleChange} />
然後就新增我們的handleClick並加入dispatch,所以payload的應用,就跟api body一樣,我們可以用在上傳購物車等各種產品,所以功能很強大
const handleClick=async(e)=>{
e.preventDefault();
dispatch({type:start_login})//
try{
const res = await axios.post("/auth/login",loginData)
console.log(res)
dispatch({type:login_success,payload:res.data.userDetails})
}catch(error){
console.log(error.response)
dispatch({type:login_failure,payload:error.response.data})
}
}
然後記得補上onClick
<button className="submit" onClick={handleClick}>登入</button>
並成功後我們可以讓登入成功跟註冊成功一樣跳到首頁,所以一樣補上 useNavigate()
然後一樣小細節設置,紅字體醒等等的與註冊成功會有的成功特效,這邊就不附上原始碼,但大家可以自己練習看看
dispatch抓取user資料並顯示在navbar,並新增我們的登出鈕
const { user, dispatch } = useContext(LoginContext);
const handleClick = (e) => {
dispatch({ type: logout })
}
<><span className='username'>{user.username}</span>
<button className="navButton" onClick={handleClick}>登出</button></>
這邊navbar可以回去排版一下間距等等的抓一下
接下來我們就要進到新的篇幅來共同處理我們的search資料,並沿用到我們的contextApi
contextApi的用法不一定在後端串接資料的應用上,只要是需要暫存器的情況都可以使用,甚至只是做夜間模式與日間模式都可以使用context來轉換所有物件的型態,
這一次我們要將所有Searchbar的搜尋資料都可以放入contextApi,就像外掛購物車的感覺,所有搜尋條件包括用戶所選的可以訂房的時間、幾位大人、哪裏的城市等等的,且因為這邊是UI面的行為操作紀錄,不會到後端,所以不會有loading的問題,只需要宣告初始值,所以我們有兩個地方可以使用到contextApi的dispatch上傳,並也有未來會需要在把state抓下來的地方
所以我們先搞定好ContextApi與dispatch上傳的部分即可,抓取資料可以等我們一起先把我們的SearchItem串接到後端,顯示真實資料後,一次一併顯示我們的搜尋條件在飯店資料上。
所以這邊我們先來設立我們的optionsContextApi
在我們有搜尋的地方一個在homePage、一個在hotelsList中都使用dispatch,來把資料上傳,等於是在案搜尋時同時更新到initial_state,
const INITIAL_STATE ={
city: "",
options: {
adult:1,
children:0,
room:1,
},
date: []
}
export const OptionsContext = createContext(INITIAL_STATE);
const OptionsReducer =(state,action)=>{
switch (action.type){
case new_Options:
return action.payload ;
case reset_Options:
return INITIAL_STATE ;
default:
return state
}
}
export const OptionsContextProvider =({children})=>{
const [state,dispatch]=useReducer(OptionsReducer,INITIAL_STATE)
return(
<OptionsContext.Provider
value={{
city:state.city,
date:state.date,
options:state.options,
dispatch,
}}>
{children}
</OptionsContext.Provider>
)
}
並這邊我們並沒有把options新增到localStorage,只要存在context內,但不代表不能存進去,也是可以一樣存入localStorage,看你想不想把這些使用者行為紀錄在localStorage內如下,這邊可以自行判斷要不要加,但我這邊選擇不加,因為做到後面時,我希望搜尋的物件可以不用被存在localStorage也就是只要F5重新整理就會消失,不然如果有使用localstorage你重整後搜尋紀錄還是在,都無法清空,只能覆寫,且如果之後我們是希望如果他沒有搜尋任何東西之時是跳出推薦的物件,那會一直沒有辦法靠f5重整頁面清空我們的localstorage,要清空只能靠清空cookie,
所以使用者可能會覺得不舒服,且預設city為台北也可以為空值,所以如果你希望你的使用者在使用網站時,搜尋類的東西案f5是消失的話,可以跟我一樣,在這邊contextApi不計入localstorage
所以這邊的如果要串接localStorage我會把他當作查看我傳上去了什麼的工具,所以下面都是帶有localstorage的版本,但正式上線我會將它拿掉,且初始值我都會進行微更改看哪些搜尋起來最為順暢。完成contextApi後,我們要來將串連我們的使用者行為操作資料
所以homePage的header中的searchBar,我們按下搜尋按鈕的同時把操作資料更新到context中。
const { city,date,options,dispatch } = useContext(OptionsContext);
搭配在handleSearchBarSubmit函數內的
dispatch({type:new_Options,payload:{city:destination,date:dates,options:conditions}})
這邊完成後,我們換去hotelsListPage讓他也能在搜尋之時,一樣按搜尋的同時也同步更新。
完成後進入到hotelsList的搜尋,真的搜尋出資料的第二大重點功能,將使用get method加上搜尋欄filter的實作也就是將context中的資料應用到query的各種混合實作,且會發現contextApi的強大與簡潔,但其中對payload與dispatch的應用觀念可能會需要有些陣疼期,但對完成幾次後就會發現其實概念沒有很難,難的是難在名詞的背誦上。