2차 공부/TIL

24.09.04 팀프로젝트 trouble shooting

공대탈출 2024. 9. 4. 01:34
const PostItemList = ({ songs, title, index }) => {
    const [isListOpen, setIsListOpen] = useState(false);

    const a = matchMedia("screen and (min-width: 1660px)");
    const b = matchMedia("screen and (min-width: 1200px) and (max-width: 1659px)");
    const c = matchMedia("screen and (min-width: 840px) and (max-width: 1199px)");
    const d = matchMedia("screen and (max-width: 839px)");

    // const [aa, setAA] = useState(matchMedia("screen and (min-width: 1660px)"))
    // useEffect(()=>{

    // }, [window.innerWidth])

    return (
        <PostItemWrapper $index={index}>
            <PostWrapTitle>{title}</PostWrapTitle>
            <PostItemsDiv $isListOpen={isListOpen}>
                {songs.length ? (
                    songs.map((music) => {
                        return <PostItem key={music.id} music={music} />;
                    })
                ) : (
                    <p>어울리는 음악이 없습니다! 해당 계절에 어울리는 음악을 추가해주세요!</p>
                )}
            </PostItemsDiv>
            {a.matches && songs.length > 4 ? (
                <ListOpenButton $index={index} $isListOpen={isListOpen} onClick={() => setIsListOpen(!isListOpen)}>
                    {isListOpen ? "▲" : "▼"}
                </ListOpenButton>
            ) : null}
            {b.matches && songs.length > 3 ? (
                <ListOpenButton $index={index} $isListOpen={isListOpen} onClick={() => setIsListOpen(!isListOpen)}>
                    {isListOpen ? "▲" : "▼"}
                </ListOpenButton>
            ) : null}
            {c.matches && songs.length > 2 ? (
                <ListOpenButton $index={index} $isListOpen={isListOpen} onClick={() => setIsListOpen(!isListOpen)}>
                    {isListOpen ? "▲" : "▼"}
                </ListOpenButton>
            ) : null}
            {d.matches && songs.length > 1 ? (
                <ListOpenButton $index={index} $isListOpen={isListOpen} onClick={() => setIsListOpen(!isListOpen)}>
                    {isListOpen ? "▲" : "▼"}
                </ListOpenButton>
            ) : null}
        </PostItemWrapper>
    );
};

PostItemWrapper가 grid로 되어있고, repeat(4, 1fr)로 되어있고 특정 width구간마다 행의 아이템 개수가 달라져 드롭다운 버튼이 보이게 했어야 했다.

근데 누가봐도 저 코드는 말이 안됐다. 저게 무슨 코드인가 쓰레기지

어쨋든 그래서 방법이 떠오르지 않아 튜터님을 찾아갔다.

 

원하는건 이렇게 드롭다운이 없었지만 페이지가 작아지면서 반응형 디자인에 의해 grid 속성이 변경되고, 그에따라 드롭다운 메뉴가 생기는 것이었다.

 

결국 내가 원하는 버튼이 생기고 사라지는건 리렌더링을 유발해야 했다. 따라서 특정 width값에 도달할때마다 setState를 작동시켜 state의 변경에따른 리렌더링을 진행시키고, 그 setState를 어떻게 실행시킬지 만들어 내야했다.

 

튜터님은 window.event resize를 추천해주셨다.

resize이벤트는 화면의 크기가 변경될 때 발생하여 컴포넌트가 로드되었을 때 addEventListener을 실행하고, 컴포넌트가 언마운트 될 때 removeEventListener을 실행시키면 되는 것 이었다.

const [visibleCount, setVisibleCount] = useState(initializeVisibleCount(4));

useEffect(() => {
    const handleByResize = () => {
        if (largeScreen.matches) {
            return setVisibleCount(4);
        } else if (mediumScreen.matches) {
            return setVisibleCount(3);
        } else if (smallScreen.matches) {
            return setVisibleCount(2);
        } else if (extraSmallScreen.matches) {
            return (1);
        }
    };
    window.addEventListener("resize", handleByResize);

    return () => {
        window.removeEventListener("resize", handleByResize);
    };
});

이렇게 resize가 될때마다 handleByResize함수를 실행시키고, matchMedia.matches를 사용하여 특정 width 범위에 들어갔을 때 setState를 특정 숫자로 변경하도록 하였다.

 

근데 이렇게하니까 문제가 있었는데, 페이지가 어느 크기에서 열리든지 visibleCount값이 4로 초기화되어 작은화면에서 크기를 변경하지 않는 한 버튼이 있어야 할 곳에 안생기는 문제였다.

 

const largeScreen = matchMedia("screen and (min-width: 1660px)");
const mediumScreen = matchMedia("screen and (min-width: 1200px) and (max-width: 1659px)");
const smallScreen = matchMedia("screen and (min-width: 840px) and (max-width: 1199px)");
const extraSmallScreen = matchMedia("screen and (max-width: 839px)");

const initializeVisibleCount = () => {
    if (largeScreen.matches) {
        return 4;
    } else if (mediumScreen.matches) {
        return 3;
    } else if (smallScreen.matches) {
        return 2;
    } else if (extraSmallScreen.matches) {
        return 1;
    }
};
const [visibleCount, setVisibleCount] = useState(initializeVisibleCount());

useEffect(() => {
    const handleByResize = () => {
        setVisibleCount(initializeVisibleCount());
    };
    window.addEventListener("resize", handleByResize);

    return () => {
        window.removeEventListener("resize", handleByResize);
    };
});

따라서 단순하게 숫자를 반환해주는 함수를 만들고 handleByResize에서 setState안에 함수를 실행시켜 적당한 값이 들어가도록 변경했으며,

컴포넌트 최초 렌더링 시에도 화면 크기에 맞는 숫자가 state의 초기값으로 들어가도록 설정하였다.


리액트를 공부하면 할수록 리렌더링에 대해 더 생각이 많아지는 것 같다.

프로젝트에서 잘못된 데이터요청과 context사용으로 리렌더링을 잡지 못한 문제가 있었고, 그것 때문에 기능하나를 아예 특정 페이지에서 없앤 것도 있다.

리렌더링을 생각하여 페이지의 효율을 높이고 더 좋고 효율적인 페이지를 만들기위해 더 생각해야 할 시간인 것 같다.