-
Notifications
You must be signed in to change notification settings - Fork 117
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[길수진] week20 #1083
The head ref may contain hidden characters: "part4-\uAE38\uC218\uC9C4-week20"
[길수진] week20 #1083
Changes from 1 commit
e07640b
b4adfa0
c10719d
baf6573
097b2ce
1a1ffed
4750f55
603e888
6771c68
e3f5c91
e2b8034
2f80437
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,49 +3,31 @@ import styles from "./navbar.module.css"; | |
import Profile from "./Profile/Profile"; | ||
import { ROUTE_PATHS } from "constants/route"; | ||
import Logo from "@/images/logo.svg"; | ||
import useFetch from "hooks/useFetch"; | ||
import useGetUser from "hooks/useGetUser"; | ||
|
||
type User = { | ||
id: number; | ||
created_at: string; | ||
name: string; | ||
image_source: string; | ||
email: string; | ||
auth_id: string; | ||
}; | ||
|
||
function Navbar() { | ||
const getUser = () => { | ||
const { data, loading, error } = useFetch<{ data: User[] }>( | ||
ROUTE_PATHS.user | ||
); | ||
const UserData = data?.data ?? []; | ||
|
||
if (error) { | ||
console.log(error); | ||
} | ||
const Navbar = () => { | ||
const { data, isError, isPending } = useGetUser(); | ||
|
||
return { data: UserData, loading, error }; | ||
}; | ||
|
||
const { data: user, loading, error } = getUser(); | ||
if (isPending) { | ||
return <></>; | ||
} | ||
|
||
return ( | ||
<nav className={styles.navbar}> | ||
<div className={styles.wrap}> | ||
<Link href={ROUTE_PATHS.home}> | ||
<Logo width="133" height="24" alt="로고" priority /> | ||
</Link> | ||
{user.length !== 0 ? ( | ||
{isError ? ( | ||
<Link href={ROUTE_PATHS.login}>로그인</Link> | ||
) : ( | ||
<Link href={ROUTE_PATHS.home}> | ||
<Profile email={user[0].email} imgUrl={user[0].image_source} /> | ||
<Profile email={data.email} imgUrl={data.image_source} /> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 저 같은 경우에는 보통 data라는 값으로 반환하기 보다는 hook에서 꺼내올때 user에 관한 정보면 userInfo라던지 조금 더 명확한 네이밍을 쓰는데 참고해보시면 좋을 것 같아요! |
||
</Link> | ||
) : ( | ||
<Link href={ROUTE_PATHS.login}>로그인</Link> | ||
)} | ||
</div> | ||
</nav> | ||
); | ||
} | ||
}; | ||
|
||
export default Navbar; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import { useQuery } from "@tanstack/react-query"; | ||
import instance from "lib/axios"; | ||
import useAuthStore from "store/authStore"; | ||
import { ROUTE_PATHS } from "constants/route"; | ||
|
||
interface UserResponse { | ||
id: number; | ||
name: string; | ||
image_source: string; | ||
email: string; | ||
} | ||
|
||
const fetchUser = async (): Promise<UserResponse> => { | ||
const { | ||
data: [user], | ||
} = await instance.get("/users"); | ||
return user; | ||
}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 해당 부분은 api 폴더를 활용해봐도 좋을 것 같아요! |
||
|
||
const useGetUser = () => { | ||
return useQuery({ | ||
queryKey: ["user"], | ||
queryFn: fetchUser, | ||
}); | ||
}; | ||
|
||
export default useGetUser; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import { useMutation } from "@tanstack/react-query"; | ||
import instance from "lib/axios"; | ||
import useAuthStore from "store/authStore"; | ||
import Cookies from "js-cookie"; | ||
|
||
interface User { | ||
email: string; | ||
password: string; | ||
} | ||
|
||
const useLogin = () => { | ||
const setAccessToken = useAuthStore((state) => state.setAccessToken); | ||
|
||
const mutation = useMutation({ | ||
mutationFn: (data: User) => { | ||
return instance.post("/auth/sign-in", data); | ||
}, | ||
onSuccess: (res) => { | ||
// 토큰 저장 | ||
const { accessToken, refreshToken } = res.data; | ||
setAccessToken(accessToken); | ||
Cookies.set("refreshToken", refreshToken, { expires: 7 }); | ||
}, | ||
onError: (error) => { | ||
throw error; | ||
}, | ||
}); | ||
|
||
const login = async (data: User) => { | ||
mutation.mutate(data); | ||
}; | ||
|
||
return { | ||
login, | ||
isPending: mutation.isPending, | ||
isSuccess: mutation.isSuccess, | ||
}; | ||
}; | ||
|
||
export default useLogin; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import { useMutation } from "@tanstack/react-query"; | ||
|
||
import instance from "lib/axios"; | ||
|
||
interface User { | ||
email: string; | ||
password: string; | ||
} | ||
|
||
const useSignUp = () => { | ||
const checkEmailMutation = useMutation({ | ||
mutationFn: (email: string) => { | ||
return instance.post("/users/check-email", { email }); | ||
}, | ||
onError: (error) => { | ||
throw error; | ||
}, | ||
}); | ||
|
||
const signUpMutation = useMutation({ | ||
mutationFn: (data: User) => { | ||
return instance.post("/auth/sign-up", data); | ||
}, | ||
onSuccess: (data) => { | ||
// 페이지 이동 | ||
}, | ||
onError: (error) => { | ||
throw error; | ||
}, | ||
}); | ||
|
||
const signUp = async (email: string, password: string) => { | ||
try { | ||
await checkEmailMutation.mutateAsync(email); | ||
await signUpMutation.mutateAsync({ email, password }); | ||
} catch (error) { | ||
throw error; | ||
} | ||
}; | ||
|
||
return { | ||
signUp, | ||
isPending: checkEmailMutation.isPending || signUpMutation.isPending, | ||
}; | ||
}; | ||
|
||
export default useSignUp; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,28 +4,31 @@ import type { | |
AxiosRequestConfig, | ||
AxiosError, | ||
} from "axios"; | ||
import { TOKEN } from "constants/auth"; | ||
import useAuthStore from "store/authStore"; | ||
|
||
const instance = axios.create({ | ||
baseURL: process.env.NEXT_PUBLIC_API_URL, | ||
headers: { "Content-Type": "application/json" }, | ||
}); | ||
|
||
const onRequest = (config: InternalAxiosRequestConfig) => { | ||
// 매 요청마다 localStorage의 토큰을 조회해서 헤더에 추가한다. | ||
if (localStorage.getItem(TOKEN.access)) { | ||
const accessToken = JSON.parse(localStorage.getItem(TOKEN.access) ?? ""); | ||
config.headers.Authorization = accessToken ? `Bearer ${accessToken}` : ""; | ||
const accessToken = useAuthStore.getState().accessToken; | ||
|
||
if (accessToken) { | ||
config.headers.Authorization = `Bearer ${accessToken}`; | ||
} | ||
|
||
return config; | ||
}; | ||
|
||
const onError = (error: AxiosError) => { | ||
// Unauthorized 응답을 받으면 가지고 있던 토큰을 제거한다. | ||
if (error.isAxiosError && error.response?.status === 401) { | ||
localStorage.removeItem(TOKEN.access); | ||
console.log(error.response.status); | ||
// Unauthorized 응답 | ||
if (error.isAxiosError) { | ||
if (error.response?.status === 404) { | ||
console.log("존재하지 않는 유저"); | ||
} else { | ||
console.log("인증 오류"); | ||
} | ||
Comment on lines
+26
to
+31
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 404와 같은 에러는 범용적인 에러라서 |
||
} | ||
}; | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { create } from "zustand"; | ||
import { persist } from "zustand/middleware"; | ||
|
||
interface AuthState { | ||
accessToken: string | null; | ||
setAccessToken: (token: string | null) => void; | ||
} | ||
|
||
const useAuthStore = create<AuthState>()( | ||
persist( | ||
(set) => ({ | ||
accessToken: null, | ||
setAccessToken: (token) => set({ accessToken: token }), | ||
}), | ||
{ | ||
name: "auth-storage", | ||
getStorage: () => localStorage, | ||
} | ||
) | ||
); | ||
Comment on lines
+9
to
+20
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. zustand도 잘 활용해주셨네요 👍🏻 클라이언트 상태관리로 최근에 가장 관심받는 라이브러리가 하나가 zustand인데 특징들을 잘 파악해두면 좋을 것 같아요! |
||
|
||
export default useAuthStore; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
api 요청을 hook으로 관리하려는 시도 너무 좋은 것 같아요👍🏻