ํฐ์คํ ๋ฆฌ ๋ทฐ
2025.02.13 (๋ชฉ) Works
1. supabase ํน๊ฐ
2. git conflict & issue ์ปจํผ๋ฐ์ค
3. Prettier ํ์ผ ๊ด๋ฆฌ
4. Home ํ์ด์ง UI ๊ตฌํ
5. supabase์์ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ
Home ํ์ด์ง UI ๊ตฌํ

๊ฐ๋จํ ๋ง๋ค์ด ๋ณธ Home UI
index.css์ body ์คํ์ผ์ ์ ์ง ์ค์ด๋ผ ํค๋๊ฐ ์งง๊ฒ ๋์จ๋ค.
์ง๊ธ์ div๋ก ์ฃผ์์ง๋ง ์ถํ์ ํ๋กํ ์ฌ์ง๊ณผ post ์ฌ์ง์ผ๋ก ๋์ฒดํ ์์ ์ด๋ค.
Supabase
DOM์ ํตํด ํ๋ฉด ์ปดํฌ๋ํธ์ ์ ๊ทผํ๊ณ ,
React๋ฅผ ํตํด ์ํ ๊ด๋ฆฌ๋ฅผ ํ๊ณ ,
Redux, Context๋ฅผ ํตํด props๋ฅผ ์ ์ญ์ ์ผ๋ก ๊ด๋ฆฌํ๊ณ ,
RRD๋ฅผ ํตํด ํ์ด์ง๋ฅผ ์ด๋ํ๊ณ ,
RTK๋ฅผ ํตํด store๋ฅผ ์์ฑํ์ฌ ๊ฐํธํ๊ฒ ๋ฐ์ดํฐ๋ฅผ ๊ด๋ฆฌํ์๋ค.
์ด๋ฒ ํ๋ก์ ํธ์์๋ ์ด์ ๋ด์ฉ๋ค๊ณผ ํจ๊ป supabase๋ฅผ ํตํ user ์ ๋ณด ๊ด๋ฆฌ๊ฐ ์ฃผ๋ ๊ธฐ๋ฅ์ด๋ค.
๐๋ด๊ฐ ์ดํดํ supabase
๊ฐ๋ตํ ์ ์ด๋ณด์๋ฉด ์๋์ ๊ฐ๋ค.
์ฌ์ฉ์๊ฐ ๋ฑ๋กํ ์ ๋ณด(ํ์๊ฐ์ )์ ์ ๋ ฅํ ์ ๋ณด(๊ฒ์๊ธ, ์ฌ์ง ๋ฑ)์ supabase๋ผ๋ DB์ ์ ์ฅํ๋ค.
์ ์ฅ๋ ๋ฐ์ดํฐ๋ key : value pair๋ก ์์ ๊ณผ ๊ฐ์ ํ์ ์ ๋ฆฌ๋๋ค.
supabase ์ธก์์ ๋ง๋ API๊ฐ ์๋๋ฐ ๊ทธ๊ฒ๋ค์ ์ฌ์ฉํด์ ๋ฐ์ดํฐ๋ฅผ ๊ด๋ฆฌํ ์ ์๋ค.
์ฌ์ฉ์ ์ ๋ณด๋ฅผ ์ ๋ ฅํ๊ฑฐ๋ ๊ฐ์ ธ์ฌ ์ ์๊ณ ,
ํ์๊ฐ์ /๋ก๊ทธ์ธ ์ฌ๋ถ์ ๋ฐ๋ผ ์ฌ์ฉ ๊ถํ์ ์ค๋ค.(๊ถํ๊ณผ ๊ด๋ จ๋ ์์ธํ ๋ด์ฉ์ ์ฌํ์ฃผ์ฐจ์์)
supabase์๋ ๋ค์ํ API๊ฐ ์์ผ๋ฉฐ ๊ทธ ๋ด์ฉ์ ๊ณต์ ๋ฌธ์์์ ๋ค๋ฃจ๊ณ ์๋ค.
https://supabase.com/dashboard/project/btdmubmenrbrjydmwwcx/api?page=users
API | Supabase
supabase.com
๐supabase ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ
๊ทธ ์ค ์ค๋์ ์์๋ก ์ ๋ ฅํ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์์ ํ๋ฉด์ ๋ํ๋ด๋ณด์๋ค.
๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ๋ก์ง์ ๋ค์๊ณผ ๊ฐ๋ค.
// App.jsx
import { createClient } from "@supabase/supabase-js";
import { useEffect } from "react";
// ์ธ์1 : ํ๋ก์ ํธ ์ฃผ์
// ์ธ์2 : ์ต๋ช
ํค
const supabase = createClient(
"https://<project>.supabase.co",
"<your-anon-key>"
);
const App = () => {
useEffect(() => {
const getTodos = async () => {
try {
const { data, error } = await supabase.from("todos").select("*");
if (error) throw error;
console.log(data);
} catch (error) {
console.log(error);
}
};
getTodos();
}, []);
return <div>App</div>;
};
export default App;
useEffect()๋ฅผ ํตํด ์ต์ด ๋ ๋๋ง ์, ์ํ๋ ํ ์ด๋ธ์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์จ๋ค.
ํ๋ก์ ํธ ์ฃผ์์ ์ต๋ช ํค๋ .env ํ์ผ์์ ๋ฐ๋ก ์ ์ธํ๋ค.
// .env
VITE_APP_SUPABASE_URL = "https://<project>.supabase.co"
VITE_APP_SUPABASE_ANON_KEY = "<your-anon-key>"
๊ทธ๋ฆฌ๊ณ client.js ํ์ผ์์ ๋ ๋ณ์๊ฐ์ผ๋ก createClient() ๋ฅผ ํตํด supabase์ ์ฐ๋์ด ๋๋ค.
// client.js
import { createClient } from "@supabase/supabase-js";
const SUPABASE_PROJECT_URL = import.meta.env.VITE_APP_SUPABASE_URL;
const SUPABASE_ANON_KEY = import.meta.env.VITE_APP_SUPABASE_ANON_KEY;
const supabase = createClient(SUPABASE_PROJECT_URL, SUPABASE_ANON_KEY);
export default supabase;
๋ด๊ฐ ๊ตฌํํ Home ํ์ด์ง์ ๋ฉ์ธ ๊ฒ์๊ธ ์นด๋์๋
users, posts, comments ์ธ ํ ์ด๋ธ์ ๊ฐ์ด ํ์ํ๋ค.
| user ์ ๋ณด(ํ๋กํ ์ฌ์ง, ๋๋ค์, MBTI) post ์ฌ์ง ๊ฒ์๋ฌผ ๋๊ธ |
์๋ ๋ฐฉ์๋ค์ ์ ๋ ๊ฑด์ง ํ์ ์ด ๋ค์ง ์์ง๋ง ์ฐ์ ์ถ๋ ฅ์ ๋๋ค..!
์ถํ ๋ณ๋์ฌํญ์ด ์์ ๋ฏ ํ์ง๋ง ์ฐ์ ๊ธฐ๋กํด๋๊ฒ ๋ค.
useEffect ์ธ ๊ฐ๋ฅผ ์จ์ผํ๋..? ์ถ์์ง๋ง ํ์ ๋ถ์ ์กฐ์ธ์ผ๋ก Promise.all ์ ์ฌ์ฉํ๋ค.
const Home = () => {
const [posts, setPosts] = useState([]);
const [users, setUsers] = useState([]);
const [comments, setComments] = useState([]);
useEffect(() => {
const fetchData = async () => {
try {
const [
{ data: postsData, error: postsError },
{ data: usersData, error: usersError },
{ data: commentsData, error: commentsError },
] = await Promise.all([
supabase.from("posts").select("*"),
supabase.from("users").select("*"),
supabase.from("comments").select("*"),
]);
if (postsError) throw postsError;
if (usersError) throw usersError;
if (commentsError) throw commentsError;
setPosts(postsData);
setUsers(usersData);
setComments(commentsData);
} catch (error) {
console.error("Error fetching data:", error);
}
};
fetchData();
}, []);
supabase.from("posts").insert({ posts });
supabase.from("users").insert({ users });
supabase.from("comments").insert({ comments });
console.log("posts", posts);
console.log("users", users);
console.log("comments", comments);
return (
<StHomeMain>
<StHeader>
<StSearchInput placeholder="๊ฒ์์ฐฝ" />
<h2>FootPrint</h2>
<Link to={"/login"}>
<StLoginBtn>๋ก๊ทธ์ธ/ํ์๊ฐ์
</StLoginBtn>
</Link>
</StHeader>
<StCategory>
<div>์ ์ฒด</div>
<div>๊ตญ๋ด</div>
<div>ํด์ธ</div>
</StCategory>
{/* postCard */}
<StHomeCard>
<StCardTop>
<StProfileImg />
{users.map(user => (
<StCardTextWrap key={user.id}>
<StNickName>{user.nick_name}</StNickName>
<StMbti>{user.mbti}</StMbti>
</StCardTextWrap>
))}
</StCardTop>
<StPostImg />
<StIcons>
<img src="../assets/icon_comment.png" alt="comment img" />
<img src="../assets/icon_heart_fill.png" alt="heart img" />
</StIcons>
{comments.map(e => (
<StComents key={e.id}>{e.text}</StComents>
))}
</StHomeCard>;
</StHomeMain>
);
};
๐จ์ด๋ ๊ฒ ์์ฑํ๊ฒ ๋๋ฉด ์ ์ฅ๋ user์ ์ ๋ณด๊ฐ ํ ์นด๋ ๋ด์ ์ผ๋ ฌ๋ก ๋จ๊ฒ ๋๋ค.
๊ฐ์ฅ ํท๊ฐ๋ฆฌ๋ ๊ฒ์ ๊ฐ ํ ์ด๋ธ์์ ์ฌ์ฉํ๋ id๋ค์ด๋ค.
users์๋ ์ฌ์ฉ์ ๋ก๊ทธ์ธ ์ id, auth์์ ์ง์ ๋ uuid
posts์๋ uuid, post์ id
comments์๋ uuid, post์ id, comment์ id
๊ฐ ์ฃผ์ด์ง๋ค.
๊ฐ id์ ์ญํ ์ ์๊ฒ ์ง๋ง ์ด๋ป๊ฒ ์ฐ๊ฒฐ๋์ด์๋์ง, ํ๋์ ์นด๋์์ ์ถ๋ ฅํ๊ธฐ ์ํ ๋ก์ง์ ๋ฌด์์ผ์ง ํท๊ฐ๋ฆฐ๋ค.
๋ํ ํ์ฅ๋์ ๊ณ์ ์ผ๋ก supabase ํ๋๋ฅผ ์ฌ์ฉํ๊ณ ์๊ธฐ ๋๋ฌธ์ ์ ๋์ ์ผ๋ก ๊ฐ์ ๋ณ๋ํ๊ธฐ๊ฐ ์ด๋ ค์ ๋ค.
๋ฐ๋ผ์ ๋ด์ผ์ ํ์ ๋ถ๊ป์ 'ํธ๋ฆฌ๊ฑฐ'๋ฅผ ์์ฑํด์ฃผ์ ์ ํ์ ๊ฐ์์ ๊ณ์ ์์ DB ์ ์ฅ ์ ๋ณด๋ฅผ ํ์ธํ ์ ์๋ค๊ณ ํ๋ค!
๋ด์ผ์ ํธ๋ฆฌ๊ฑฐ์ ๋ํ ๋ด์ฉ์ ์ตํ๊ณ , supabase๋ฅผ ์ง์ ๋ค๋ค๋ณด๋ฉฐ ์ ์ฅ ์ ๋ณด๋๋ก ์นด๋๋ฅผ ์ฐ์ด๋ณด๋ ค๊ณ ํ๋ค.
Tomorrow Task
- supabase API ์ตํ๊ธฐ
- ํธ๋ฆฌ๊ฑฐ ์ตํ๊ธฐ
- DB ์ ๋ณด ๊ฐ์ ธ์ค๊ธฐ (๊ฐ ํ ์ด๋ธ์ id ๊ตฌ๋ณํ๊ธฐ)
'Forntend > TIL' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| [NewsFeed-Day 4] Modal ์ฐ๊ฒฐ (0) | 2025.02.15 |
|---|---|
| [NewsFeed-Day 3] supabase ๋ฐ์ดํฐ ๋๊ธฐํ (1) | 2025.02.15 |
| ๊ตฌ์กฐ๋ถํดํ ๋น (Context ์ฌ์ฉ ์์) (0) | 2025.02.10 |
| TIL | 09 (0) | 2025.01.24 |
| ๋ฐ์ฑ... (1) | 2025.01.23 |