๐ผ ํด๋ฆญ์ ์ฌ์ดํธ ์ด๋
- 2023.03.29 ~ 2023.04.27
- Home
- Product Detail Page
- My Cart
- New Product ( admin๊ถํ์ด ์๋ ์ฌ์ฉ์๋ง ๋ณด์ด๋ ํ์ด์ง ) ๊ด๋ฆฌ์๋ง ์์ํ ๋ฑ๋ก
- Login, Logout ( ๊ตฌ๊ธ๊ณ์ ๋ก๊ทธ์ธ )
โ ์ค๋ฅ ์ฌํญ
Navbar์์ useState
๋ฑ๋ก | useEffect
์ ํตํด user์ ๋ณด๋ฅผ Component์ ๋ฑ๋กํ์๋๋, ํ์ด์ง ๋ฆฌ๋ก๋ฉ์ ์ ๋ณด ์ด๊ธฐํ ์ ์ ์ ๋ณด๋ฅผ ๊ฐ์ง๊ณ ์์ง ๋ชปํ๋ ์ค๋ฅ๊ฐ ๋ฐ์ํ์์ต๋๋ค.
- ์์ ๋ด์ฉ
Context Api ์ด์ฉํด user๋ฅผ ๋ฑ๋ก Navbar์์useAuthContext
๋ก <AuthContext.Provider/>๋ก ๊ฐ์ผ ์ปดํฌ๋ํธ์์ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์ ์ ์๋๋ก ์ค์ ํ์๊ณ , ๋ฆฌ๋ก๋ฉ์์๋ ์ ์ ์ ๋ณด ๋ณด๊ด
๐ฌ์ฝ๋๋ณด๊ธฐ
/**๋ก๊ทธ์ธ, ๋ก๊ทธ์์ ๊ฒฐ๊ณผ๊ฐ๋ฐ๋ํจ์ */
export function onUserStateChange(callback) {
onAuthStateChanged(auth, async (user) => {
const updatedUser = user ? await adminUser(user) : null;
callback(updatedUser);
});
}
๏ผ login(), logout()
์ ๋ช
๋ นํ ํจ์๋ก๋ง ์ด์ฉ
- ์ด๋๋ฏผ ์ฌ์ฉ์ ๊ฒฝ๋ก๋ณดํธ index.js
<ProtectedRoute/>
์ฌ์ฉํ์ฌ ProtectedRoute.jsx Component์์ ์กฐ๊ฑด์ ์ฒดํฌํ๋ค route๋ฅผ์ด์ฉํด ์์ํ๋ฑ๋กํ์ด์ง๋ก ์ด๋ํ ์ ์๊ฒํ์์ต๋๋ค.( ๋ก๊ทธ์ธํ ์ฌ์ฉ์ํ์ธ, ์ด๋๋ฏผ๊ถํ์ฒดํฌ )
๐ฌ์ฝ๋๋ณด๊ธฐ
import React from 'react';
import { useAuthContext } from '../context/AuthContext';
import { Navigate } from 'react-router-dom';
export default function ProtectedRoute({children, requireAdmin}){
const { user } = useAuthContext();
console.log(user,'๋ ๋ผ์ฐํฐํ์ด์ง์ ์ ์ ์ ๋ณด ๋จ๋์ง ์ข')
if(user===undefined){
return <>๋ก๋ฉ์ค</>;
} else if (user === null || (requireAdmin && user.isAdmin===false)) {
return <Navigate to={"/"} replace={true} />;
} else {
return children;
}
}
//๋ก๊ทธ์ธํ ์ฌ์ฉ์๊ฐ ์๋์งํ์ธ
//์ฌ์ฉ์๊ฐ ์ด๋๋ฏผ ๊ถํ์ด ์๋์ง ํ์ธ
//requireAdmin์ด true์ธ ๊ฒฝ์ฐ์๋ ๋ก๊ทธ์ธ๋ ๋์ด์์ด์ผํ๊ณ , ์ด๋๋ฏผ ๊ถํ๋ ๊ฐ์ง๊ณ ์์ด์ผํจ\
//์กฐ๊ฑด์ด ๋ถ์ถฉ์กฑํ ๊ฒฝ์ฐ / ์์ ๊ฒฝ๋ก๋ก ์ด๋
//์กฐ๊ฑด์ด ์ถฉ์กฑ๋๊ฒฝ์ฐ ์ ๋ฌ๋ chidren์ ๋ณด์ฌ์ค
๐ฌ์ํ๊ด๋ฆฌ ๊ถํ ์ฝ๋๋ณด๊ธฐ
/**์ํ๊ด๋ฆฌ ๊ถํ ์ฒดํฌ */
//firebase/admins์ ๋ฏธ๋ฆฌ ๊ถํ์์ค uid๋ฅผ ๋ฑ๋ก
async function adminUser(user) {
return get(ref(database, "admins")).then((snapshot) => {
if (snapshot.exists()) {
const admins = snapshot.val();
console.log(admins);
const isAdmin = admins.includes(user.uid);
return { ...user, isAdmin };
}
return user;
});
}
๐ (์์ ์ ) ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ
const {
isLoading,
error,
data: products,
} = useQuey(["products"], getProducts, { staleTime: 1000 * 60 });
- (์์ ํ)
custom hook
์ฌ์ฉ ํ ์ฝ๋๋ฆฌํฉํ ๋ง โจ
const {
productsQuery: { isLoading, error, data: products },
} = useProducts();
reactQuery
์ ์ง๋ณด์ ์ฉ์ด, UI/business ๋ก์ง ๋ถ๋ฆฌํ๊ธฐ ์ํด custom hook
์ ์ด์ฉํด ์์ฒญ/ ์
๋ฐ์ดํธ๋ฅผ ํ๊ณณ์์ ๊ด๋ฆฌํ๊ฒ ์์ ํ์์ต๋๋ค.
์ฅ๋ฐ๊ตฌ๋์ ๋ด๊ธด ๊ฐ์๋ฅผ ๋ฐ๋ก ํ์ธํ์ง ๋ชปํ์์ผ๋, firebaseํ์ผํจ์๋ฅผ component์์ ์ฌ์ฉํ์ง์๊ณ
custom hook์์ ํจ์๋ฅผ ๋ฐ์์ mutate(์ ๋ณด)
๋ฅผ ์ด์ฉํด ์ ๋ฌ -> ์๋ฒ์์ ๋ฐ์ดํฐ๋ฅผ ์ฌํธ์ถํด ์ต์ ์ํ๋ก ์
๋ฐ์ดํธ
cart custom hook ์ฝ๋
๐ฌ์์ธํ๋ณด๊ธฐ
export default function useCart() {
const queryClient = useQueryClient();
const { uid } = useAuthContext();
/**์ฌ์ฉ์๋ณ๋ก ์บ์ ์ฌ์ฉ์๊ฐ ์๋๊ฒฝ์ฐ์๋ง apiquery์ฌ์ฉ */
const cartQuery = useQuery(["carts", uid || ""], () => getCart(uid), {
enabled: !!uid,
});
const addOrUpdateItem = useMutation(
(product) => addOrUpdateToCart(uid, product),
{
onSuccess: () => {
queryClient.invalidateQueries(["carts", uid]);
},
}
);
const removeItem = useMutation((id) => removeFromCart(uid, id), {
onSuccess: () => {
queryClient.invalidateQueries(["carts", uid]);
},
});
return { cartQuery, addOrUpdateItem, removeItem };
}
export async function uploadImage(file) {
const data = new FormData();
data.append("file", file);
//secret key => .env
data.append("upload_preset", process.env.REACT_APP_CLOUDINARY_PRESET);
return fetch(process.env.REACT_APP_CLOUDINARY_URL, {
method: "POST",
body: data,
})
.then((res) => res.json())
.then((data) => data.url);
}
- ์ฌ๊ธฐ์ ์ด๋ฏธ์งURL์ ๋ฐ์์ firbase์ ํ์ผํํ X => urlํํ๋ก ์ถ๊ฐํ์์ต๋๋ค.