[React] React 완벽 가이드 섹션 9 : 프레그먼트 작업, Portals & Ref
https://www.udemy.com/course/best-react/
1. jsx 제한 사항 및 해결 방법
- 루트 요소는 1개여야만 한다
- 그 이유는 자바스크립트 자체가 원래 하나의 요소만 반환하기 때문
// 자바스크립트에서 아래 문법은 불가능 하다
return (
React.createElement('h2',{}, 'hi');
React.createElement('h2',{}, 'hi');
);
1) 해결 방법
ⓐ 여러개의 요소를 하나의 <div>태그(아무태그)로 감싼다. => div soup 발생, 불필요한 렌더링 과정 실행
* div soup : div태그가 중첩되어 스타일링이 깨질 수도 있고, 속도가 느려질 수도 있다.
ⓑ 배열형태로 반환한다. => 경고 발생 키가 필요하기 때문
그래서 이상적인 해결방법?
👉 Wrapper 컴포넌트 생성. 단지 children만을 반
const Wrapper = (props) => {
return props.children;
}
export default Wrapper;
사실 생성할 필요는 없다. 리액트에서 제공하기 때문
return (
<React.Fragment>
...
</React.Fragment>
)
return (
<>
...
<>
)
위 두가지 방식중 하나를 쓰면 된다. (실제 html요소를 dom에 렌더링 하지 않음)
2. Portals
- 오버레이 안에 있는 모달이 깊게 중첩되는 문제를 해결하기위해 나온 개념
- modal 컴포넌트는 html요소의 가장 위에 오도록 해야된다...
why? 모달은 전체 페이지에 대한 오버레이이다. 그리고 스타일링이나 접근성 관점에서 문제 발생 우려
>> html에서 컴포넌트의 코드위치를 조정할 수 있다 ! !
1) 사용 방법
2개가 필요 : 컴포펀트를 이동시킬 장소, 컴포넌트에게 그곳에 포털을 가져야 한다고 알려줘야 함
- index.html에서 div태그 구조를 만들어 준다. (index.html이 아니어도 상관없다 ! portal 시킬 장소)
...
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="backdrop-root"></div>
<div id="overlay-root"></div>
<div id="root"></div>
</body>
...
- 끌어올릴 컴포넌트에서 리액트 돔을 불러온다. (react18에서는 react-dom/client)
import ReactDOM from "react-dom";
- createPortal을 이용하여 컴포넌트를 끌어올린다.
return(
<> {ReactDom.createPortal( jsx요소, 끌어올릴 위치} </>
// ReactDom.createPortal(<Error />, document.getElementById('backdrop-root'))
);
모달을 작성한 코드 위치에 상관 없이 내가 지정한 위치로 이동하여 렌더링 된다.
3. ref
- 실제 dom요소에 접근하여 그것들로 작업할 수 있도록 해주는 것
- 하지만 dom의 요소들을 변경하는 것은 지양해야한다. 보통은 값을 빠르게 읽어오고 싶을 때 사용 !
useRef는 하나의 객체를 반환하는데, 그 객체는 current라는 속성을 갖고 있다.
current는 ref랑 연결된 실제 값을 가진다. 기본 값은 useRef()안 정의된 초기값이지만
코드가 실행된 후에는 연결된 dom 요소 가지게 된다.
1) 사용 방법
- useRef를 import 한다.
import { useRef } from "react";
- ref로 받아올 변수 선언
const nameInputRef = useRef();
const ageInputRef = useRef();
- form 태그에서 ref로 dom 요소를 접근시에 아래처럼 사용
<form onSubmit={addUserHandler}>
<input id="username" type="text" ref={nameInputRef} />
<input id="age" type="number" ref={ageInputRef} />
<Button type="submit">Add User</Button>
</form>
- ref로 선언한 변수는 객체를 반환한다.
그리고 변수이름.current.(실제 돔에서 사용되는 속성) 으로 접근 가능
const enteredName = nameInputRef.current.value;
const enteredUserAge = ageInputRef.current.value;
// 초기화 (dom에 직접 접근)
nameInputRef.current.value = '';
ageInputRef.current.value = '';
- 위와 같이 실제 돔의 input.value 속성을 가져와서 사용 가능하다.
- state나 ref 둘 중 적합한 방식으로 선택하여 사용하면 된다.
- 단순히 값을 읽는 행위는 state를 이용하지 않는게 낫다. ref를 이용하여 dom에 접근하는게 낫다.
* 제어되는 컴포넌트와 제어되지 않는 컴포넌트
- ref로 읽어온 값을 이용하는 컴포넌트는 react의 ref의 기능을 이용하는 것이지 제어되는 컴포넌트는 아니다..
- 해당 컴포넌트는 내부 state이기 때문에 내부 값들은 리액트에 의해 제어되지 않는다.
- ref를 이용해서 단지 가져오는 것에 불과
- input 요소는 브라우저에 의해 내부 state를 갖는 경향이 있다.
- 만약 value를 react state를 이용해 관리한다면 제어되는 컴포넌트라 할 수 있다.