2차 공부/TIL

24.08.29 팀프로젝트 진행 - Startify

공대탈출 2024. 8. 29. 20:56

이번 팀프로젝트는 내배캠에서 react로 진행하는 첫 팀프로젝트이다. 우리팀은 노래를 공유하는 사이트를 만들기로 결정하였다.

로그인과 회원가입으로 유저정보를 저장하고, 로그인한 사용자에 한하여 게시글 작성같은 인터랙션을 허용한다.

게시글은 supabase에 아직 익숙하지않아 영상데이터는 youtube url을 사용하여 iframe으로 보여주기로 하였다.

노래마다 게시글제목, 노래제목, 가수명, 어울리는 계절, 해시태그를 입력하여 서버에 데이터를 보내고

각 데이터뭉치들을 메인페이지에서 계절마다의 탭으로 나눠 보여준다.

각 게시글 카드는 좋아요를 추가할 수 있으며, 좋아요 범위 외를 클릭하면 해당 카드의 상세페이지로 이동하게된다.

그리고 로그인, 회원가입을 제외한 모든 페이지에는 Layout컴포넌트를 생성하여 동일한 헤더가 적용될 수 있도록 설정하였다.

 

오늘은 메인페이지의 MockView를 만들고, 서버에 Mock Data를 추가하고, 해당 데이터로 화면에 보여주도록 고치는 작업을 하였다.

import { useEffect, useState } from "react";
import supabase from "../supabaseClient";
import styled from "styled-components";
import PostItemList from "../components/home/PostItemList";

const Home = () => {
    const [songs, setSongs] = useState({ "전체": [], "봄": [], "여름": [], "가을": [], "겨울": [] });
    const getAllData = async () => {
        const { data, error } = await supabase.from("STARTIFY_DATA").select("*");
        if (error) {
            console.log("getAllData error :>> ", error);
            return;
        } else {
            setSongs((prev) => {
                const updated = JSON.parse(JSON.stringify(prev));
                data.forEach((music) => {
                    const { genre } = music;
                    if (updated[genre]) {
                        updated[genre] = [...updated[genre], music];
                    }
                });
                return updated;
            });
        }
    };
    useEffect(() => {
        getAllData();
    }, []);
    return (
        <ListWrapper>
            <PostItemList title="언제나 듣기 좋은 노래" musics={songs["전체"]} />
            <PostItemList title="봄에 듣기 좋은 노래" musics={songs["봄"]} />
            <PostItemList title="여름에 듣기 좋은 노래" musics={songs["여름"]} />
            <PostItemList title="가을에 듣기 좋은 노래" musics={songs["가을"]} />
            <PostItemList title="겨울에 듣기 좋은 노래" musics={songs["겨울"]} />
        </ListWrapper>
    );
};

export default Home;

아직 context API를 사용하지않아 props로 자식컴포넌트에 내려주었다.

컴포넌트가 처음 렌더링되면 useEffect안의 getAllData함수에 의해 supabase서버로부터 데이터를 모두 받아온다.

그리고 받아온 데이터를 각 계절별로 나누어 songs State에 담는다.

그리고 songs의 각 계절별 데이터를 props로 내려준다.

 

import React from "react";
import PostItem from "./PostItem";
import styled from "styled-components";

const PostItemList = ({ title, musics }) => {
    return (
        <PostItemWrapper>
            <PostWrapTitle>{title}</PostWrapTitle>
            <PostItemsDiv>
                {musics.length ? (
                    musics.map((music) => {
                        return <PostItem key={music.id} music={music} />;
                    })
                ) : (
                    <p>어울리는 음악이 없습니다! 해당 계절에 어울리는 음악을 추가해주세요!</p>
                )}
            </PostItemsDiv>
        </PostItemWrapper>
    );
};

export default PostItemList;

받은 데이터를 PostItem컴포넌트를 사용해 페이지에 알맞은 동일한 형태로 보여지게 된다.


오늘 작업을 진행하며 서버에서 받아온 데이터를 계절에 따라 분리하는데서 문제가 있었다.

const [songs, setSongs] = useState({ 전체: [], 봄: [], 여름: [], 가을: [], 겨울: [] });
const getAllData = async () => {
    const { data, error } = await supabase.from("STARTIFY_DATA").select("*");
    if (error) {
        console.log("getAllData error :>> ", error);
        return;
    } else {
        setSongs((prev) => {
            const updated = JSON.parse(JSON.stringify(prev));
            data.forEach((music) => {
                const { genre } = music;
                if (updated[genre]) {
                    updated[genre] = [...updated[genre], music];
                }
            });
            return updated;
        });
    }
};

서버에 저장된 각 계절명은 문자열이다. 하지만 songs 객체 안의 키값들은 prettier에 의해 문자열이 아닌 어떤 타입으로 변경되었다.

그래서 각 계절명과 해당 게시물의 계절명을 비교하지 못해 state에 저장을 하지 못했다.

//.prettierrc
{
    "quoteProps": "preserve"
}

이는 prettier의 quote-props 설정때문이었다. 해당 설정은 객체의 키이름을 자동으로 변경해주는 것이라고 이해를 했는데(정확하지 않음) 그 값이 자동으로 변경되도록 default값이 잡혀있어 보존하는 preserve로 설정을 추가하여 계절명 비교오류를 해결하였다.


오늘 밤~ 내일하루는 검색페이지 mock view를 잡을 것이고, 시간이 남는다면 context를 사용하여 props drilling을 해결할 것이다.