퍼플렉시티의 경우 출처 모두 표시 버튼을 클릭하면 출처 레이어가 770px 이상일 때는 채팅 화면 우측 레이어로 나타나고, 770px 이하일 때는 바텀시트로 나타납니다.


제가 만들고 있는 채팅 화면에서도 위와 같은 출처 레이어를 적용하면서 반응형 처리를 해주려고 합니다.
현재 MUI 컴포넌트를 활용 중이고,
breakpoint는 600px,
600px 이상일 때: 레이어 형태
600px 이하일 때: 바텀시트 대신 Drawer(외부 레이어) 형태로 적용 하려고 합니다.
처음엔 아래와 같이 코드를 작성했으나 Too many re-renders. React limits the number of renders to prevent an infinite loop. 에러가 발생했습니다.
// sm: 600px 이상이면 레이어 형태를 변경
const smUp = useMediaQuery((theme: Theme) => theme.breakpoints.up('sm'));
const DrawerWrapper = ({ children }: { children: React.ReactElement }) => {...}
const LayerWrapper = ({ children }: { children: React.ReactElement }) => {...}
const ChildrenContent = () => {...}
return (
<>
{smUp ? (
<DrawerWrapper>
<ChildrenContent />
</DrawerWrapper>
) : (
<LayerWrapper>
<ChildrenContent />
</LayerWrapper>
)}
</>
);
Too many re-renders 에러는 React 컴포넌트가 렌더링 중에 상태를 변경하거나, 무한 루프를 유발하는 코드를 실행했을 때 발생합니다. 제공된 코드에서 무한 렌더링이 발생하는 주요 원인은 다음과 같을 수 있습니다.
smUp 계산 중 상태 변경useMediaQuery 훅 내부에서 상태 변화를 트리거하거나, theme와 관련된 상태가 계속 변경되는 경우 무한 루프가 발생할 수 있습니다.
useMediaQuery가 호출될 때 React가 계속해서 컴포넌트를 재렌더링하도록 유발하는 상황일 가능성이 있습니다.
ChildrenContent 컴포넌트 재정의ChildrenContent 컴포넌트가 렌더링 시마다 새로운 정의로 간주될 가능성이 있습니다. 즉, 컴포넌트가 재정의되면서 React가 다시 렌더링 트리거를 반복적으로 실행할 수 있습니다.
-> 해당 사항 없음
DrawerWrapper와 LayerWrapper의 상태 또는 동작내부적으로 상태 관리나 부수효과(hook)를 포함하고 있다면, 렌더링마다 상태가 변경될 가능성을 점검해야 합니다.
-> 해당 사항 없음
제 코드의 경우, useMediaQuery에 안정적인 값을 전달할 필요가 있었습니다.
theme.breakpoints를 계산할 때 사용자가 브라우저를 리사이징 하여 smUp 값이 변경될 위험이 있습니다. 따라서, 안정성을 위해 useMemo (또는 useCallback)로 감싸서 캐싱하였습니다.
// as-is
const smUp = useMediaQuery((theme: Theme) => theme.breakpoints.up('sm'));
// to-be
const smUp = useMediaQuery(useMemo(() => theme.breakpoints.up('sm'), [theme]));
완성된 화면입니다.
600px 이상일 땐 채팅 화면 내부에 레이어로 뜨게 되고,
이하일 땐 채팅 화면 외부 레이어로 뜨게 되었습니다.
