ํ‹ฐ์Šคํ† ๋ฆฌ ๋ทฐ

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
๊ณต์ง€์‚ฌํ•ญ
์ตœ๊ทผ์— ์˜ฌ๋ผ์˜จ ๊ธ€
์ตœ๊ทผ์— ๋‹ฌ๋ฆฐ ๋Œ“๊ธ€
Total
Today
Yesterday
๋งํฌ
TAG
more
ยซ   2026/03   ยป
์ผ ์›” ํ™” ์ˆ˜ ๋ชฉ ๊ธˆ ํ† 
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
๊ธ€ ๋ณด๊ด€ํ•จ