로그인 처리
우리가 구현할 기능은 로그인 후 로그인 성공 페이지까지 진행할 것 이므로, 로그인 폴더와 로그인 성공 폴더 두개를 만들어 주자
// login 폴더의 index.tsx 화면 그려주기
import {useMutation,gql} from "@apollo/client"
import {ChangeEvent} from "react"
cosnt LOGIN_USER = gql`
mutation loginUser($email:String){
loginUser(email: $email, password: $password){
accessToken
}
}
`
export default function LoginPage(){
const [email,setEmail]=useState("")
const [password,setPassword]=useState("")
const [loginUser] = useMutation<Pick<IMutation,'loginUser'>,IMutationLoginUserArgus>(LOGIN_USER)
const onChangeEmail = (event:ChangeEvent<HTMLInputElement>)=>{
setEmail(event.target.value)
}
const onChangePassword = (event:ChangeEvent<HTMLInputElement>)=>{
setPassword(event.target.value)
}
const onClickLogin = async()=>{
try{
cosnt result = await loginUser({
variables:{
email : email,
password : password
}
})
const accessToken = result.data?.loginUser.accessToken
}catch(error){
// alert(error.message)을 사용하셔도 무방합니다.
Modal.error({content : error.message})
}
}
return(
<div>
이메일 : <input type="text" onchange={onChangeEmail}/> <br/>
비밀번호 : <input type="password" onchange={onChangePassword}/>
<button onClick={onClickLogin}>로그인하기!!</button>
</div>
)
}
loginUser같은 경우엔 타입 추론이 불가능하다
이럴때 우리는 앞에는 받아올 타입을 , 뒤에는 보내줄 타입을 직접 적어준다
입력하는 방법으로는 IMutation에서 로그인 유저의 타입을 Pick 해줘야 한다
우리는 loginsuccess에서 로그인 한 유저의 정보를 가지고 오고 있다
유저의 정보를 가지고 오는 api를 사용할 것 인데, 사용을 위해 http header부분에 accessToken을 첨부해서 요청해야 한다
const onClickLogin = async (): Promise<void> => {
try {
// 1. 로그인 뮤테이션 날려서 accssToken 받아오기
const result = await loginUser({
variables: {
email,
password,
},
})
const accessToken = result.data?.loginUser.accessToken
console.log(accessToken)
// 2. 받아온 accessToken을 globalState에 저장하기
if (accessToken === undefined) {
alert("로그인에 실패했습니다. 다시 시도해주세요!")
return
}
SetAccessToken(accessToken)
// SetAccessToken(accessToken ?? "")
// 3. 로그인 성공 페이지로 이동하기
void router.push("/section23/23-01-login-success")
} catch (error) {
if (error instanceof Error) alert(error.message)
}
}
1. 로그인 뮤테이션 날려서 accssToken 받아오기
2. 받아온 accessToken을 globalState에 저장하기
3. 로그인 성공 페이지로 이동하기
예상치 못한 실패 catch로 관리
error 타입 지정 (error instanceof Error)
이렇게 토큰을 같이 보내주도록 세팅을 하면, 유저의 정보를 받아와 화면에 “재훈님 환영합니다.”와 같이 정보를 띄울 수 있게 된다
// loginsuccess 폴더의 index.tsx
const FETCH_USER_LOGGED_IN = gql`
query fetchUserLoggedIn{
fetchUserLoggedIn{
email
name
}
}
`
export default function LoginSuccessPage(){
const {data} = useQuery<Pick<IQuery,"fetchUserLoggedIn">>(FETCH_USER_LOGGED_IN)
return(
<div>
{data?.fetchUserLoggedIn.name}님 환영합니다.
</div>
)
}
global state에 저장된 accessToken header 연동하기
//app.tsx파일
import { RecoilRoot } from "recoil";
function MyApp({ component,pageProps }:AppProps){
return (
<RecoilRoot>
<ApolloSetting>
<Global styles={globalStyles} />
<Layout>
<Component {...pageProps} />
</Layout>
</ApolloSetting>
</RecoilRoot>
)
}
// src/components/commons/apollo/index.tsx
export default function ApolloSetting(props: IApolloSettingProps): JSX.Element {
const [accessToken] = useRecoilState(accessTokenState)
const uploadLink = createUploadLink({
uri: "백엔드 주소",
headers: { Authorization: `Bearer ${accessToken}` },
})
const client = new ApolloClient({
link: ApolloLink.from([uploadLink]),
cache: GLOBAL_STATE, // 컴퓨터의 메모리에다가 백엔드에서 받아온 데이터 임시로 저장
})
위의 uploadLink에 저 토큰을 추가했다는 것은, 모든 컴포넌트에서 로그인 관련 토큰을 추가해서 보내주도록 한 것이다
Recoil에 accessToken을 저장해두고 사용하고싶은 컴포넌트 전체를 감싸주고 필요한 곳에서 꺼내서 사용하자
'TIL' 카테고리의 다른 글
apollo-cache-state (0) | 2023.07.22 |
---|---|
카카오 지도 연동 (0) | 2023.07.22 |
recoil (0) | 2023.07.05 |
global state (0) | 2023.07.05 |
검색 기능 구현 (0) | 2023.07.04 |