해당 내용은 https://www.udemy.com/course/best-react/ 강의를 들으며 정리하고 스스로 공부 한 내용을 기록 하였습니다.
리액트를 천천히 배워가고 있는 시점에서 한가지 의문점이 생겼다.
return (
<h2>Hi there! </h2>
<p>This does not work </p>
);
해당 코드처럼 작성할 순 없는걸까? 실제로 작성해보면 빨간 줄 표시가 뜨면서 root Element
가 필요하다고 나온다.
return (
<div>
<h2> Hi there! </h2>
<p> This does not work :-( </p>
</div>
);
이처럼 div
태그 혹은 사용자가 정의한 컴포넌트 등의 어떤 요소를 감싸주어야 정상적으로 작동이 된다.
그러면 각각의 컴포넌트가 전부 div
태그로 감싸주게 된다면..?
<div>
<div>
<div>
<div>
...
</div>
</div>
</div>
</div>
이렇게 렌더링 되었을 때에 div
의 늪에 빠지지 않게 되지 않을까 라는 한계점을 확인 할 수 있다.
이에 대한 한계점을 우리는 Wrapper Component
를 만들어 해소 시킬 수 있다.
const Wrapper = (props) => {
return props.children;
};
export default Wrapper;
이러한 컴포넌트를 만들어주어서 div
태그의 늪에 대해 빠져나갈 수 있다.
위의 방법처럼 Wrapper component
를 만들어주어 사용해도 되지만, 리액트에서 지원을 해주고 있는데, 그 중 하나는 바로 <React.Fragment>
이다. 혹은 <> </>
를 이용하여도 된다.
import React, { useState, Fragment } from "react";
function App() {
...
return (
<Fragment>
...
</Fragment>
);
}
export default App;
하지만 위의 방법에서는 아쉬운 부분이 있는데, 바로 전체 페이지에 대한 오버레이를 하는 모달에 있어서 아쉬운 부분이 있다.
return (
<React.Fragment>
<MyModal />
<MyInputForm />
</React.Fragment>
);
해당 코드는 문제가 없으며 실제로 화면을 작동할 때에도 문제가 없어보일 수 있지만, HTML 구조로 보았을 때 (시멘틱구조) 좋은 구조는 아니다.
// Real DOM
<section>
<h2> Content ... </h2>
<div class="my-modal">
<h2> Modal ... </h2>
</div>
<form>
<label> Username </label>
<input type="text" />
</form>
</section>
모달은 전체 페이지에 대한 오버레이다. 모든 것 위에 있는 것을 의미하는데, 스타일링이나 접근성의 관점에서도 문제가 생길 수 있다.
만약 오버레이 내용이 중첩 되어 있다면 스크린 리더가 렌더링 되는 HTML코드를 일반적인 오버레이라고 인식하지 못할 수 있다. 또한 의미적인 관점이나 구조적인 관점으로 보았을 떄 에도 HTML 코드 안 깊은 곳에 자리 잡고 있다.
이러한 부분을 Portals
를 이용해서 해소 시킬 수 있다. 포탈을 이용하여 해당 부분을 해소 시켜보자.
포탈은 우선적으로, 컴포넌트를 이동시킬 장소와 그 후에 컴포넌트 에게 그 곳에 포탈을 가져야 한다고 알려줄 필요가 있다.
import ReactDOM from "react-dom";
return (
<React.Fragment>
{ReactDOM.createPortal()}
</React.Fragment>
);
ReactDOM.creatProtal()
document.createElementId()
를 작성한다. 실제 HTML DOM요소에 접근 가능하다.import React from "react";
import ReactDOM from "react-dom";
const Backdrop = (props) => {
return <div className={classes.backdrop} onClick={props.onConfirm} />;
};
const ModalOverlay = (props) => {
return (
<Card className={classes.modal}>
<header className={classes.header}>
<h2>{props.title}</h2>
</header>
<div className={classes.content}>
<p>{props.message}</p>
</div>
<footer className={classes.actions}>
<Button onClick={props.onConfirm}>Okay</Button>
</footer>
</Card>
);
};
const ErrorModal = (props) => {
return (
<React.Fragment>
{ReactDOM.createPortal(
<Backdrop onConfirm={props.onConfirm} />,
document.getElementById("backdrop-root")
)}
{ReactDOM.createPortal(
<ModalOverlay
title={props.title}
message={props.message}
onConfirm={props.onConfirm}
/>,
document.getElementById("overlay-root")
)}
</React.Fragment>
);
};
export default ErrorModal;
💡 포털의 핵심은 렌더링 된 HTML요소를 다른 곳으로 옮기는 것이다.
기본적으로 다른 DOM 요소에 접근해서 그것들로 작업을 할 수 있게 해주는 도구이다.
마지막에 렌더링 되는 HTML요소들과 다른 자바스크립트 코드의 연결한다.
-> useRef훅 이용 - 함수형 컴포넌트 안에서만 사용 가능하다.
어떤 HTML 요소라도 참조 중 하나에 연결 할 수 있다.
항상 객체, 항상 current프롭을 가지고 있으며, ref의 실제 값 갖게 된다.
const nameInputRef = useRef();
const ageInputRef = useRef();
// ex
nameInputRef.current.value
데이터 값 만 빠르게 읽고 싶으며 변경 계획이 없다면 ref를 이용하는 것도 좋은 방법이다.
보통 인풋 필드에서 많이 이야기 하는데, 리액트에서 제어를 하냐/ 안하냐 에 따라 용어가 바뀐다.
state 를 사용했을 때는 입력을 할 떄 마다 state에 저장을 하고 … value는 state에서 값을 꺼내오고.. 이와 같은 부분을 제어 된 컴포넌트라고 이야기 하지만, ref 같은 경우에는 제어되지 않는 컴포넌트라고 말을 한다.