오늘은 PR의 날.. 그리고 마이페이지 아직도 적용 못하는 나란 babo...
간단하게 뜨라블 슈팅 적구 가야징... (총총)
Mypage - 마이페이지 모달... 뜨라블 슈팅
문제 상황
마이페이지를 요번에는 라우터를 활용한 페이지 구현이 아닌..
모달을 활용하기로 한 림졍. (일단 해보자고 마인드.)
여튼 우다다다 호로록 CSS 작성부터 하고....(대충 ) 나오는 것을 확인한 뒤,
Nav에 옮겨 클릭 시, 마이페이지가 나오게끔 코드를 구현하였는데..
모달이 딱 해당 부분에서만 나오게끔 만들어진 것이다.!!!
알고보니 Nav 컴포넌트의 DOM 구조 안에서 렌더링되었기 때문에
width가 Nav의 CSS 속성을 상속받아 고정되게 되어 모달의 레이아웃이 의도치 않게 깨지게 되었달까..
원인 분석
React의 기본 렌더링 방식에서는 컴포넌트가 부모 DOM 계층 구조에 종속되어
MyPage 모달이 Nav 내부에 렌더링되어 스타일 상속 발생으로 인해 width가 Nav의 크기로 제한되었다는 것을 알 수 있었다!
해결 방법
이 문제를 해결하기 위해 ReactDOM.createPortal()을 사용하여 MyPage 모달을 Nav DOM 계층 밖으로 렌더링했습니다. 이렇게 하면 모달이 독립적인 DOM 노드에 렌더링되어 Nav의 스타일링에 영향을 받지 않게 됩니다.
- 수정된 코드
1. ReactDOM.createPortal() 사용
- 모달을 document.getElementById('portal-root')에 렌더링하도록 수정
2. HTML 파일 수정
- index.html에 portal-root 추가 → 모달이 렌더링될 DOM 노드 정의
<!-- index.html -->
<body>
<div id="root"></div>
<div id="portal-root"></div> <!-- 포털 루트 추가 -->
</body>
3. React 코드 수정
- MyPage 모달의 렌더링 부분을 ReactDOM.createPortal을 사용하도록 변경
// ReactDOM.createPortal을 사용하여 MyPage 모달을 독립적인 DOM 노드에 렌더링
return ReactDOM.createPortal(
<div
className="fixed top-0 left-0 w-full h-screen bg-black bg-opacity-50 flex items-center justify-center z-50"
onClick={onClose}
>
<div
className="bg-white rounded-[20px] w-full max-w-sm p-10 relative overflow-y-auto max-h-[90vh] shadow-xl"
onClick={(e) => e.stopPropagation()}
>
{/* 닫기 버튼 */}
<button
className="absolute top-4 right-4 text-[#666] hover:text-[#333] text-[32px]"
onClick={onClose}
>
<IoClose />
</button>
{/* 헤더 */}
<h2 className="text-[28px] text-[#333] text-center">My Page</h2>
<div className="mt-8">
<ProfileImageUploader setImage={setNewImage} />
</div>
{/* 닉네임 입력 */}
<div className="mt-10">
<form
onSubmit={handleSubmit(handleNicknameUpdate)}
className="flex flex-wrap items-center gap-4"
>
<NicknameInput
register={register}
setError={setError}
clearErrors={clearErrors}
errors={errors}
watch={watch}
setValue={setValue}
trigger={trigger}
/>
</form>
</div>
{/* 업데이트 버튼 */}
<div className="flex justify-center items-center mt-8 gap-4">
<button
onClick={async () => {
if (newImage) {
await handleProfileImageUpdate();
}
if (isValid) {
await handleNicknameUpdate(watch());
}
}}
disabled={!newImage && !isValid}
className={`w-40 py-3 rounded-full font-semibold text-white ${
newImage || isValid
? 'bg-[#FFB200] hover:bg-[#FF8D03]'
: 'bg-gray-300 cursor-not-allowed opacity-60 grayscale'
}`}
>
업데이트
</button>
</div>
</div>
</div>,
document.getElementById('portal-root') // 포털 루트에 렌더링
);
결과
ReactDOM.createPortal()을 통해 MyPage 모달이 Nav DOM 계층 외부로 렌더링
→ 이로 인해 Nav의 width 값을 상속받는 문제 해결 및 모달의 레이아웃, 독립적 적용 완료
마무리
ReactDOM.createPortal()은 DOM 계층을 벗어난 곳에 UI를 렌더링할 때 매우 유용하다!
→ 이를 통해 모달, 툴팁, 알림 등과 같은 UI 컴포넌트를 효과적으로 구현이 가능해져
모달이 딱 해당 부분에서만 나오게된다 . . . ^0^
뜨러블 슈팅 끝! 이얏호 ^-^)b
'React TIL' 카테고리의 다른 글
[React] Day_55 팀 프로젝트 후기 (4) | 2024.12.05 |
---|---|
[React] Day_54 팀 프로젝트 작업 관련 트러블슈팅 (2) (0) | 2024.12.04 |
[React] Day_52 데일리 정리 (0) | 2024.12.02 |
[React] Day_51 개인 프로젝트 후기 (2) | 2024.11.29 |
[React] Day_50 데일리 정리 (2) | 2024.11.28 |