
์๋ต ๊ตฌ์กฐ ์ดํด์ ์ด๋ ค์:
updateProfile ํจ์์์ API ํธ์ถ ํ response.data ํํ๋ก ๋ฐ์ดํฐ๋ฅผ ๋ฐํ๋ฐ์์.
Network ํญ์ ํตํด API ์๋ต์ ํ์ธํ๋๋ { accessToken, avatar, nickname, success, userId } ํํ์์.
์ด๋ก ์ธํด response.nickname๊ณผ response.data.nickname ์ค ์ด๋ ์ชฝ์ ์ฌ์ฉํด์ผ ํ ์ง ํผ๋์ค๋ฌ์ ์.
์ํ ๊ด๋ฆฌ ์ด์:
์ํ๋ฅผ ์
๋ฐ์ดํธํ๋ ํจ์์์ ์ด์ ์ํ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์๋ก์ด ์ํ๋ฅผ ์ค์ ํ๋๋ก ๋ก์ง์ ์์ ํ์.
์๋ฅผ ๋ค์ด, setUser((prevUser) => ({ ...prevUser, nickname: response.nickname }))์ ๊ฐ์ ๋ฐฉ์์ผ๋ก ์ด์ ์ฌ์ฉ์ ์ํ๋ฅผ ๊ฐ์ ธ์์ ์
๋ฐ์ดํธํ๋ ๋ฐฉ์์ผ๋ก ํด๊ฒฐํ์.
ํน์ ํ์ด์ง์์์ ํค๋, ๋ผ์ฐํ
๋ฌธ์ :
ํค๋์ ๋ผ์ฐํ
์ค์ ์ ์งํํ ๋ ์ฌ์ฉ์๋ง ์ ๊ทผํ ์ ์๋ ํค๋์ ์๋ ๊ณตํต ํค๋๋ฅผ ๊ฐ์ง๋ ํ์ด์ง์ ๋
ผ์๊ฐ ํ์ํ์.
ํจํค์ง ๊ด๋ฆฌ ๋ฌธ์ :
ํ ํ๋ก์ ํธ์์ npm๊ณผ yarn ๊ฐ์ ์๋ก ๋ค๋ฅธ ํจํค์ง ๊ด๋ฆฌ์๋ฅผ ์ฌ์ฉํ๊ณ ์์ด, ์์กด์ฑ ๋ฌธ์ ์ ์ถฉ๋์ด ๋ฐ์ํ์.
์คํ์ผ ๋ณ๊ฒฝ์ ์ด๋ ค์:
ํ๋ก์ ํธ์์ Tailwind CSS๋ฅผ ์ฌ์ฉํ๊ณ ์์์ง๋ง, ํ์์ด styled-components๋ฅผ ์ฌ์ฉํด ์คํ์ผ๋ง์ ํด์, ๋์ค์ Tailwind ์คํ์ผ์ styled-components๋ก ๋ณ๊ฒฝํด์ผ ํ๋ ์ด๋ ค์์ด ์์์.
Zustand๋ฅผ ์ฌ์ฉํ ๋ ์ํ ๊ด๋ฆฌ๋ฅผ ์ํ store ์์ฑ
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
const useUserStore = create(
persist(
(set) => ({
user: null,
setUser: (userData) => set({ user: userData }),
clearUser: () => set({ user: null })
}),
{
name: 'user-storage', // localStorage์ ์ ์ฅ๋ ํค์ ์ด๋ฆ
getStorage: () => localStorage // localStorage๋ฅผ ์ ์ฅ์๋ก ์ฌ์ฉ
}
)
);
export default useUserStore;
store๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด useUserStore ํ
๋ฃ๊ธฐ
import { create } from "zustand";
import { persist } from "zustand/middleware";
const useUserStore = create(
persist(
(set) => ({
user: null, // ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ์ ์ฅํ ๊ณณ
accessToken: null, // ๋ก๊ทธ์ธ ์ ๋ณด๋ฅผ ํ์ธํ ์ ์๋ ํ ํฐ
setUser: (userData) => set({ user: userData }), // ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ์ ์ฅํ๋ ํจ์
setAccessToken: (token) => set({ accessToken: token }), // ํ ํฐ์ ์ ์ฅํ๋ ํจ์
clearUser: () => set({ user: null, accessToken: null }) // ์ฌ์ฉ์ ์ ๋ณด์ ํ ํฐ์ ์ง์ฐ๋ ํจ์
}),
{
name: "user-storage", // ์ํ๋ฅผ ์ ์ฅํ ๋ ์ฌ์ฉํ ์ด๋ฆ
getStorage: () => localStorage // ์ํ๋ฅผ ์ ์ฅํ ์ ์ฅ์๋ ๋ธ๋ผ์ฐ์ ์ ๋ก์ปฌ ์คํ ๋ฆฌ์ง
}
)
);
export default useUserStore;
user ์ํ:
user ์ํ์ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ์ ์ฅํ๊ณ , ์ด ์ ๋ณด๋ฅผ ์ด์ฉํด ํ๋ฉด์ ์ฌ์ฉ์ ์ด๋ฆ์ ํ์ํฉ๋๋ค.accessToken ์ํ:
accessToken์ ์ฌ์ฉํฉ๋๋ค. ์ด ํ ํฐ์ด ์ ํจํ๋ฉด ์๋ฒ์์ ์ฌ์ฉ์๋ฅผ ์ธ์ฆ๋ ์ํ๋ก ์ธ์ ํฉ๋๋ค.accessToken์ ์ ์ฅํ๊ณ , ์ด ํ ํฐ์ API ์์ฒญ์ ํค๋์ ํฌํจ์์ผ ์ธ์ฆ์ ์ํํฉ๋๋ค.setUser ํจ์:
user ์ํ๋ฅผ ์
๋ฐ์ดํธํฉ๋๋ค.user ์ํ๋ฅผ ์
๋ฐ์ดํธํฉ๋๋ค.setUser(userData)๋ฅผ ํตํด user ์ํ์ ์ ์ฅํฉ๋๋ค.setAccessToken ํจ์:
accessToken ์ํ๋ฅผ ์
๋ฐ์ดํธํฉ๋๋ค.setAccessToken(token)์ ํตํด ์ ์ฅํฉ๋๋ค. ์ดํ API ์์ฒญ ์ ์ด ํ ํฐ์ ์ฌ์ฉํฉ๋๋ค.setAccessToken(token)์ ํตํด ์ํ์ ์ ์ฅํฉ๋๋ค.๐ ์์ฝ
user: ์ฌ์ฉ์์ ๊ฐ์ธ ์ ๋ณด๋ฅผ ์ ์ฅํฉ๋๋ค.accessToken: ์ฌ์ฉ์์ ์ธ์ฆ ์ํ๋ฅผ ํ์ธํ๊ธฐ ์ํ ํ ํฐ์ ์ ์ฅํฉ๋๋ค.setUser: ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ์ ๋ฐ์ดํธํฉ๋๋ค.setAccessToken: ์ธ์ฆ ํ ํฐ์ ์ ๋ฐ์ดํธํฉ๋๋ค.
์ปดํฌ๋ํธ์์ ์ํ๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด, Zustand store์์ ํ์ํ ์ํ๋ฅผ ๊ฐ์ ธ์์ ์ปดํฌ๋ํธ์ props๋ ์ง์ ์ํ๋ฅผ ์ฌ์ฉํ์ฌ UI๋ฅผ ์ ๋ฐ์ดํธํฉ๋๋ค.
์๋ฅผ ๋ค์ด, ๋ก๊ทธ์ธ ์ํ์ ๋ฐ๋ผ ํค๋๋ฅผ ๋ณ๊ฒฝํ๋ ๊ฒฝ์ฐ:
const Layout = () => {
const { user, setUser } = useUserStore();
const handleLogout = () => {
setUser(null);
localStorage.removeItem("accessToken");
};
return (
<header>
{user ? (
<div>
<p>{`${user.nickname}๋ ์๋
ํ์ธ์!`}</p>
<button onClick={handleLogout}>๋ก๊ทธ์์</button>
</div>
) : (
<div>
<Link to="/login">๋ก๊ทธ์ธ</Link>
<Link to="/signup">ํ์๊ฐ์
</Link>
</div>
)}
</header>
);
};
- ํ ํฐ์ ์ ์ฅํ๋ ๋ฐฉ๋ฒ
- ์ ์ฅ๋ ํ ํฐ์ ์ฌ์ฉํ์ฌ ์ํ๋ฅผ ๋ณต์ํ๋ ๋ฐฉ๋ฒ
๋ณดํต, ๋ก๊ทธ์ธ ์ํ๋ฅผ ์ ์งํ๋ ค๋ฉด ๋ก์ปฌ ์คํ ๋ฆฌ์ง๋ฅผ ์ฌ์ฉํฉ๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ํ์ด์ง๋ฅผ ์๋ก ๊ณ ์นจํ๊ฑฐ๋ ๋ธ๋ผ์ฐ์ ๋ฅผ ๋ซ์๋ค ๋ค์ ์ด์ด๋ ์ฌ์ฉ์์ ๋ก๊ทธ์ธ ์ํ๋ฅผ ์ ์งํ ์ ์์ต๋๋ค.
const handleLogin = async (formData) => {
try {
const loginData = await login(formData);
localStorage.setItem("accessToken", loginData.accessToken);
} catch (error) {
alert("๋ก๊ทธ์ธ์ ์คํจํ์ต๋๋ค. ๋ค์ ์๋ํด์ฃผ์ธ์.");
}
};
์ ์ฝ๋์์๋ login API ํธ์ถ ํ, ๋ฐ์ accessToken์ ๋ก์ปฌ ์คํ ๋ฆฌ์ง์ ์ ์ฅํฉ๋๋ค.
ํ์ด์ง๋ฅผ ์๋ก ๊ณ ์น๊ฑฐ๋ ๋ธ๋ผ์ฐ์ ๋ฅผ ์ฌ์์ํ๋ฉด, ํด๋ผ์ด์ธํธ๋ ๋ก์ปฌ ์คํ ๋ฆฌ์ง์์ ์ ์ฅ๋ accessToken์ ๊ฐ์ ธ์ ์ฌ์ฉ์ ์ธ์ฆ ์ํ๋ฅผ ๋ณต์ํ ์ ์์ต๋๋ค. ์ด๋ฅผ ์ํด ์ฑ์ด ์์ํ ๋ ๋ก์ปฌ ์คํ ๋ฆฌ์ง์์ ํ ํฐ์ ํ์ธํ๊ณ ์ํ๋ฅผ ๋ณต์ํ๋ ๋ก์ง์ด ํ์ํฉ๋๋ค.
Zustand Store ์ค์
Zustand store๋ฅผ ์ค์ ํ ๋, accessToken์ ๋ก์ปฌ ์คํ ๋ฆฌ์ง์์ ์ฝ์ด์ ์ํ๋ฅผ ์ด๊ธฐํํฉ๋๋ค.
import { create } from "zustand";
import { persist } from "zustand/middleware";
const useUserStore = create(
persist(
(set) => ({
user: null,
accessToken: localStorage.getItem("accessToken") || null, // ๋ก์ปฌ ์คํ ๋ฆฌ์ง์์ accessToken ์ฝ๊ธฐ
setUser: (userData) => set({ user: userData }),
setAccessToken: (token) => {
localStorage.setItem("accessToken", token); // ๋ก์ปฌ ์คํ ๋ฆฌ์ง์ ํ ํฐ ์ ์ฅ
set({ accessToken: token });
},
clearUser: () => {
localStorage.removeItem("accessToken"); // ๋ก์ปฌ ์คํ ๋ฆฌ์ง์์ ํ ํฐ ์ ๊ฑฐ
set({ user: null, accessToken: null });
}
}),
{
name: "user-storage",
getStorage: () => localStorage
}
)
);
export default useUserStore;
์ปดํฌ๋ํธ์์ ์ํ ์ฌ์ฉํ๊ธฐ
์ํ๋ฅผ ์ฌ์ฉํ๋ ์ปดํฌ๋ํธ์์, accessToken์ด ์ ์ฅ๋ ์ํ์ธ์ง ํ์ธํ๊ณ , ํ์ํ ๊ฒฝ์ฐ API ํธ์ถ์ ํตํด ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ต๋๋ค.
import React, { useEffect } from "react";
import useUserStore from "./path/to/useUserStore";
import { getUserProfile } from "./api/auth";
const App = () => {
const { user, accessToken, setUser } = useUserStore();
useEffect(() => {
if (accessToken) {
// accessToken์ด ์กด์ฌํ๋ฉด, API๋ฅผ ํตํด ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ต๋๋ค.
const fetchUserProfile = async () => {
try {
const userProfile = await getUserProfile(accessToken);
setUser(userProfile);
} catch (error) {
console.error("์ฌ์ฉ์ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๋ ์ค ์ค๋ฅ ๋ฐ์:", error);
}
};
fetchUserProfile();
}
}, [accessToken, setUser]);
return (
<div>
{user ? <p>Welcome, {user.nickname}!</p> : <p>Please log in.</p>}
</div>
);
};
export default App;
์ด๋ ๊ฒ ์ค์ ํ๋ฉด, ์ฑ์ด ์์๋ ๋ ๋ก์ปฌ ์คํ ๋ฆฌ์ง์์ accessToken์ ์ฝ์ด์ ์ฌ์ฉ์์ ๋ก๊ทธ์ธ ์ํ๋ฅผ ์ ์งํ ์ ์์ต๋๋ค.
import axios from "axios";
const API_URL = "https://moneyfulpublicpolicy.co.kr";
export const register = async (userData) => {
const response = await axios.post(`${API_URL}/register`, userData);
return response.data;
};
export const login = async (userData) => {
const response = await axios.post(`${API_URL}/login`, userData);
return response.data;
};
...
const useUserStore = create(
persist(
(set) => ({
user: null,
accessToken: null,
setUser: (userData) => set({ user: userData })
// userData๋ฅผ user ์ํ์ ์ ์ฅํ๋ ค๊ณ
// { user: userData }๋ ์๋ก์ด ์ํ ๊ฐ์ฒด๋ก, user๋ผ๋ ์์ฑ์ userData ๊ฐ์ผ๋ก ์
๋ฐ์ดํธ ํ๊ฒ ๋ค๋ ๋ป.
// ์ํ๊ฐ ์
๋ฐ์ดํธ๋๋ฉด user์๋ ์ด์ ์ฌ์ฉ์ ์ ๋ณด๊ฐ ๋ค์ด๊ฐ๋๋ค
...
user vs. userData์ ์ญํ ์ฐจ์ดuser: ์ํ ๊ด๋ฆฌ์์ ์ฌ์ฉํ๋ ์ํ ๊ฐ์ ์๋ฏธํฉ๋๋ค. ์ฆ, Zustand์์ ๊ด๋ฆฌํ๋ user๋ ๋ก๊ทธ์ธํ ํ ์ฌ์ฉ์ ์ ๋ณด๊ฐ ์ ์ฅ๋๋ ๊ณณ์
๋๋ค.userData: ํจ์์ ๋งค๊ฐ๋ณ์๋ ์ธ๋ถ์์ ๋ฐ์ ๋ฐ์ดํฐ๋ฅผ ๋ํ๋
๋๋ค. ์๋ฅผ ๋ค์ด, ๋ก๊ทธ์ธ API์์ ๋ฐํ๋ ์ฌ์ฉ์ ์ ๋ณด ๊ฐ์ฒด๋ฅผ ๋ฐ์ ๋ userData๋ผ๋ ์ด๋ฆ์ ์ฃผ๋ก ์ฌ์ฉํฉ๋๋ค. ์ด ๊ฐ์ ํจ์์์ ์ผ์์ ์ผ๋ก ์ฌ์ฉ๋๋ ๊ฐ์
๋๋ค.์ฆ, user๋ ์ฑ ๋ด์์ ์ ์ญ ์ํ๋ก ๊ด๋ฆฌ๋๋ ์ฌ์ฉ์ ์ ๋ณด์ด๊ณ , userData๋ ์ธ๋ถ๋ก๋ถํฐ ๋ค์ด์จ ์๋ก์ด ์ฌ์ฉ์ ์ ๋ณด์
๋๋ค.
user๋ Zustand์์ ๊ด๋ฆฌํ๋ ์ํ (์ฆ, ํ์ฌ ์ฌ์ฉ์ ์ํ)userData๋ ํจ์๋ API์์ ๋ฐ์์จ ์๋ก์ด ๋ฐ์ดํฐ(์
๋ ฅ๊ฐ)์์๋ก ์ํฉ์ ๋๋ ๋ณด๋ฉด:
userData๋ฅผ ๋ฐ์์ ์ํ๋ฅผ ์
๋ฐ์ดํธconst login = async (credentials) => {
const userData = await api.login(credentials); // ์๋ฒ์์ ๋ฐ์์จ ์ฌ์ฉ์ ์ ๋ณด
setUser(userData); // ๋ฐ์์จ ๋ฐ์ดํฐ๋ฅผ ์ํ๋ก ์ ์ฅ
}
์ฌ๊ธฐ์ userData๋ API๋ก๋ถํฐ ๋ฐ์์จ ์๋ก์ด ์ฌ์ฉ์ ์ ๋ณด์ด๊ณ , setUser๋ฅผ ํตํด ์ด ๋ฐ์ดํฐ๋ฅผ Zustand์์ ๊ด๋ฆฌํ๋ user ์ํ์ ์ ์ฅํฉ๋๋ค.
user ์ฌ์ฉconst { user } = useUserStore(); // Zustand์์ ์ํ ๊ฐ์ ธ์ค๊ธฐ
console.log(user); // ์ด๊ฑด ํ์ฌ ์ ์ฅ๋ ์ฌ์ฉ์ ์ํ์
๋๋ค.
์ด์ฒ๋ผ userData๋ ์ธ๋ถ์์ ์๋ก ๋ค์ด์ค๋ ๊ฐ์ด๊ณ , user๋ ์ด๋ฏธ ์ ์ฅ๋ ์ํ ๊ฐ์ด๊ธฐ ๋๋ฌธ์ ์ด๋ฆ์ ๋ค๋ฅด๊ฒ ํด์ ํผ๋์ ์ค์ธ๋ค!!
user๋ ์ ์ญ ์ํ๋ก ์ฑ ์ ์ฒด์์ ์ฌ์ฉ๋๋ ์ฌ์ฉ์ ์ ๋ณด.userData๋ ์ธ๋ถ์์ ๋ฐ์์ค๋(api) ์๋ก์ด ๋ฐ์ดํฐ.