2차 공부/TIL

24.09.02 팀프로젝트 진행상황

공대탈출 2024. 9. 2. 22:44

원래 메인페이지와 검색페이지에서 보여지는 아이템 하나마다 좋아요를 추가, 취소할수 있는 기능을 넣고자 하였다.

하지만 모든 데이터가 한 객체로 관리되고 있었다.

const [total, setTotal] = useState({'전체':[], '봄':[], ...생략})

이런식으로 한 객체에 키값을 달리해 관리하고있었는데

    const toggleLikedSearched = async (isLiked, postId, e) => {
        e.stopPropagation();
        if (!userId) {
            let goToSignIn = confirm("로그인 후 사용가능합니다. 로그인페이지로 이동하시겠습니까?");
            goToSignIn ? navigate("/login") : null;
            return;
        }

        const { data, error } = isLiked
            ? await supabase.from("STARTIFY_LIKES").delete().match({ "user_id": userId, "post_id": postId })
            : await supabase.from("STARTIFY_LIKES").insert({ "user_id": userId, "post_id": postId });
        if (error) {
            console.log("error :>> ", error);
            return;
        }
        let updatedSearchedSongs = [...searchedSongs];
        updatedSearchedSongs = updatedSearchedSongs.map((music) => {
            if (music.id == postId) {
                const newLikesArray = isLiked
                    ? music.likes.filter((like) => like.user_id != userId)
                    : [...music.likes, { user_id: userId }];
                return { ...music, likes: newLikesArray };
            }
            return music;
        });
        setSearchedSongs(updatedSearchedSongs);

정확한 코드는 아니지만, 이런 느낌으로 관리를 하고있었는데 한가지 state로 만들어진 객체를 관리하다보니, 좋아요 함수에 의해 값이 변경되면 전체 state가 변경되고 그에따라 모든 아이템이 리렌더링 되었다.

따라서 그 문제를 조금 나누고자 계절 탭에따라 리렌더링되게 state를 5가지로 분리해보았다.

 

const [springs, setSprings] = useState([]);
const [summers, setSummers] = useState([]);
const [autumns, setAutumns] = useState([]);
const [winters, setWinters] = useState([]);
const [seasonal, setSeasonal] = useState([]);

const { user } = useContext(UserContext);
const userId = user?.id;

const initailizeStates = () => {
    setSprings([]);
    setSummers([]);
    setAutumns([]);
    setWinters([]);
    setSeasonal([]);
};

//TODO - select범위 조절해야함
const getAllData = async () => {
    initailizeStates();
    const { data, error } = await supabase.from("STARTIFY_DATA").select("*, likes:STARTIFY_LIKES(user_id)");
    if (error) {
        console.log("getAllData error :>> ", error);
        return;
    }
    data.forEach((music) => {
        const { genre } = music;
        switch (genre) {
            case "봄":
                setSprings((prev) => [...prev, music]);
                break;
            case "여름":
                setSummers((prev) => [...prev, music]);
                break;
            case "가을":
                setAutumns((prev) => [...prev, music]);
                break;
            case "겨울":
                setWinters((prev) => [...prev, music]);
                break;
            case "전체":
                setSeasonal((prev) => [...prev, music]);
                break;
            default:
                break;
        }
    });
};

이렇게 한 객체로 관리되던 state를 각각의 state로 분리하고

const updatedByLikes = (state, postId, isLiked) => {
    let updatedMusic = JSON.parse(JSON.stringify(state));
    updatedMusic = updatedMusic.map((music) => {
        if (music.id == postId) {
            const newLikesArray = isLiked
                ? music.likes.filter((like) => like.user_id != userId)
                : [...music.likes, { user_id: userId }];
            return { ...music, likes: newLikesArray };
        }
        return music;
    });
    return updatedMusic;
};
//TODO - 좋아요선택 취소 기능 작업중, 선택취소는 되는데 아직 state반영안되어 getAllData한번더할지 state만 변경할지 고민중
const toggleLiked = async (isLiked, postId, e, genre) => {
    e.stopPropagation();
    if (!userId) {
        let goToSignIn = confirm("로그인 후 사용가능합니다. 로그인페이지로 이동하시겠습니까?");
        goToSignIn ? navigate("/login") : null;
        return;
    }

    const { data, error } = isLiked
        ? await supabase.from("STARTIFY_LIKES").delete().match({ "user_id": userId, "post_id": postId })
        : await supabase.from("STARTIFY_LIKES").insert({ "user_id": userId, "post_id": postId });
    if (error) {
        console.log("error :>> ", error);
        return;
    }

    switch (genre) {
        case "봄": {
            setSprings(updatedByLikes(springs, postId, isLiked));
            break;
        }
        case "여름":
            setSummers(updatedByLikes(summers, postId, isLiked));
            break;
        case "가을":
            setAutumns(updatedByLikes(autumns, postId, isLiked));
            break;
        case "겨울":
            setWinters(updatedByLikes(winters, postId, isLiked));
            break;
        case "전체":
            setSeasonal(updatedByLikes(seasonal, postId, isLiked));
            break;
        default:
            break;
    }
};

좋아요를 누르면 해당 state만 변경되게 진행했다.

하지만 전체 데이터가 리렌더링 되었다. React.memo를 사용해서 리스트 컴포넌트도 묶어보았으나, 전체가 리렌더링 되었다.

 

그래서 state로 관리하지않고 그냥 배열로 관리해보자 했으나, 그러면 데이터가 넘어왔을때 리렌더링되지않아 불가하다 생각하여 메인과 검색페이지에서 좋아요 기능을 제외하는 것으로 마무리되었다.

 

이유는 뭘까...

생각나는 이유는 여러 state가 한 context에서 관리되기때문에 한가지가 변경되더라도 해당 context를 사용하는 모든 컴포넌트가 리렌더링되는것

이것때문이 아니면... 모르겠다 솔직히 state를 빼와 useMemo에 넣어 사용하기도 해봤고, 함수를 useCallback으로 감싸도 보았는데 솔직히 모르겠다

 

context와 redux의 큰 차이점은 리렌더링이라고 배웠지만, 그 리렌더링을 왜 막지 못하는가에 대해 한번 시간이 나면 튜터님께 여쭤보든, 해결해보든 해야할것같다.

일단 프로젝트를 완성해야해서 시간이없다.