모달은 전체 페이지에 대한 오버레이다. 따라서 당연히 모든 것의 위에 있어야 하는데, 모달과 같은 동일선상에 컨텐츠 요소들이 들어가면 바람직하지 않은 HTML 구조이다.
이는 스타일링이나 접근성의 관점에서 문제가 생길 수 있다.
리액트 포탈을 사용하면 root
안에 들어가는 모달이 아닌, 동일 선상의 위치한 모달을 웹에 구현할 수 있게 된다.
아래 코드를 보며 이해를 했다.
// React JSX
return (
<>
<MyModal/>
<MyInputForm/>
</>
)
-------------------------------------------------
// Real DOM
<section>
<h2>Sub Title Text Text..</h2>
<div class="Modal">
<h2>Modal !!</h2>
</div>
<form class="input_form">
<label>User name</label>
<input type="text">
</form>
</section>
=> class 이름으로 분간할 수 있음. React JSX 환경에서 컴포넌트를 만들고 Real DOM으로 변환하면 modal과 form이 동일하게 있는 것을 볼 수 있음.
웹에서 작동은 하겠지만, 잘못된 HTML 구조이다.
마치 button을 만드는데, <button>
을 쓰지 않고, <div>
로 버튼을 만든 느낌이랄까..
<div onClick={onAddUser} class="im_button">Add</div>
HTML 구조를 정상적이라면 이런 코드 구조가 나와야 할 것이다.
//Real DOM
<div class="Modal">
<h2>Modal !!</h2>
</div> // 모달이 레이아웃 제일 위에 올라옴
<section>
<h2>Sub Title Text Text..</h2>
<form class="input_form">
<label>User name</label>
<input type="text">
</form>
</section>
React에서 이런 구조를 만들고 싶다면, React Portal을 사용하면 된다.
index.html
파일에 id=root
와 형제인 div
를 하나 만들어준다.
{ReactDOM.createPortal(보여줄 컴포넌트, 컴포넌트를 위치시키고자 하는 index.html 파일의 div id)}
{ReactDOM.createPortal(
<ModalOverlay
title={props.title}
message={props.message}
onConfirm={props.onConfirm}
/>, // 내가 보여주고픈 컴포넌트
document.getElementById("overlay-root") // <div> id="overlay-root" </div>에 내가 보여주고픈 컴포넌트를 띄워주세요.
)}
useState
와 비슷하지만 중요한 한가지 차이점이 있다.
useRef
는 값을 변경해도 다시 렌더링되지 않는다.
즉,
useState
는 값이 변경되면, 리렌더링 되면서 값이 변경되지만,useRef
는 값이 변경되어도 리렌더링 되지 않는다.
공식 문서에서 useRef
는 화면에 표시하려는 정보는 저장하는 데 적합하지 않다고 되어있다. ➡ 화면에 표시해야하는 정보를 저장할 때는 useState
가 적합하다는 말.
그럼 useRef
언제 사용해야 하는가?
값만 빠르게 읽고 싶다면, 아무 것도 바꿀 계획이 없다면 State는 그리 필요하지 않다.
키 로그 기록용으로 State를 사용하는 것은 비효율적이다.
useState는 키 로그 기록용으로 사용하기에는 불필요한 코드와 작업이 많기 때문.
input에 값만 빠르게 읽고싶다면, ref를 사용하는 것이 더 좋은 방법일 수 있다.
또한 매우 편하고 빠르게 요소에 접근할 수 있다는 이점이 있다.
하지만 ref를 사용하게 된다면 DOM을 직접적으로 조작한다는 점이 있고
(React에서 좋아하지 않는 예외적인..)
State를 사용하면 깔끔하지만 코드를 조금 더 많이 써야하는 차이가 있을 것 같다.