react 학습하기 - UI 표현하기
연말에 React를 돌아보는 시간을 가지고 있는데 정리 내용을 저장하려고 한다.
1️⃣ 첫 번째 컴포넌트
📌 컴포넌트
컴포넌트: UI 구성 요소
React를 사용하면 마크업, CSS, JS를 앱의 재사용 가능한 컴포넌트로 구성할 수 있다.
📌 컴포넌트 정의하기
-
컴포넌트 내보내기 : export default 접두사는 표준 JS 문법. 이 접두사를 사용한다.
-
함수 정의하기 : function 함수명() {}을 사용하면 JS 함수 정의할 수 있다. 이때 함수명은 대문자로 시작해야한다. 아니면 작동하지 않는다.
-
마크업 추가하기 : JSX 문법 사용한다. 컴포넌트는 다른 컴포넌트를 렌더링 할 수 있지만, 그 정의를 중첩해서는 안된다.
📊 챌린지 리뷰
export default function Profile() {
return;
<img src="https://i.imgur.com/jA8hHMpm.jpg" alt="Katsuko Saruhashi" />;
}
- 유명한 함정. 자동으로 세미콜론을 넣어서 return문이 끝난 것으로 인식.
- 따라서 한줄로 하거나 소괄호로 묶어주면 됨.
2️⃣ 컴포넌트 import 및 export 하기
컴포넌트의 가장 큰 장점은 재사용성으로 컴포넌트를 조합해 또 다른 컴포넌트 만들 수 있다는 것이다.
React에서는 './Gallery.js' 또는 './Gallery'로 import 할 수 있다. 전자의 경우가 native ES Modules 사용법에 더 가깝다고 할 수 있다.
📌 Default와 Named Exports
| Syntax | Export 구문 | Import 구문 |
|---|---|---|
| Default | export default function Button() {} | import Button from './button.js'; |
| Named | export function Button() {} | import { Button } from './button.js'; |
보편적으로 한 파일에서 하나의 컴포넌트만 export 할 때 default export 방식을 사용하고, 여러 컴포넌트를 export 할 경우엔 named export 방식을 사용한다.
3️⃣ JSX로 마크업 작성하기
JSX는 JavaScript를 확장한 문법으로, HTML과 유사하지만 JavaScript의 특성을 유지한다.
매번 변화가 생길 때마다 서로 동기화 상태 유지할 수 있어서 편리하다.
📌 JSX의 규칙
-
반드시 하나의 루트 엘리먼트로 반환하기
HTML처럼 보이지만 내부적으로는 react element라는 순수 js 객체로 변환된다. 하나의 함수에서는 두개의 객체를 반환 할 수 없기 때문이다.
-
모든 태그 닫아주기
-
대부분 camelCase 케이스로(틀려도 콘솔에서 알려준다)
4️⃣ 중괄호가 있는 JSX 안에서 자바스크립트 사용하기
JSX 안에서 중괄호를 사용하면 자바스크립트 표현식을 사용할 수 있다.
📌 중괄호를 사용하는 곳
- jsx 태그 안의 문자.
- = 바로 뒤에 오는 어트리뷰트
📌 이중 중괄호 사용하기
jsx에서 객체를 전달하려면 중괄호 쌍으로 객체를 감싸야한다. 인라인 css스타일에서 style 어트리뷰트에 객체를 전달해야한다. 이때 camelCase로 작성해야만 한다.
<img
className="avatar"
src={`${baseUrl}${person.imageId}${person.imageSize}.jpg`}
alt={person.name}
/>
5️⃣ Props 전달하기
React 컴포넌트는 props를 통해 서로 통신한다. props는 객체, 배열, 함수를 포함한 모든 JS 값을 전달 할 수 있다.
-
props를 선언할 때, ()안에 {} 쌍을 놓치면 안된다.
-
기본값 지정하기 {name = 'Stranger'}
-
때때로 전달되는 props는 반복적일 수 있다. 이때 간결함이 중요할 때도 있다. 이때는 {...props}하면 간편하게 전달 된다.
props는 컴퓨터 과학에서 "변경 할 수 없다"라는 불변성을 가지고 있다. 따라서 변경할 때는 새로운 객체를 전달하도록 요청해야 한다. 그러면 js엔진은 기존 props가 차지했던 메모리 회수한다.
function Child(props) {
props.color = "red"; // ❌ 이렇게 재할당하면 안 됨
props.user.name = "동현"; // ❌ 객체 props 내부를 직접 mutate하는 것도 안 됨
return <div>{props.color}</div>;
}
6️⃣ 조건부 렌더링
if (isPacked) {
return null;
}
return <li className="item">{name}</li>;
return null은 흔하니까 걱정 말고 써도 된다.
📌 논리합 AND(&&)
피연산자를 왼쪽에서 오른쪽으로 평가하면서 첫 거짓 같은 피연산자를 만나면 반환. 모든 값이 참이면 마지막 값 반환.
&&의 왼쪽에 숫자를 두지마라
js는 자동으로 왼쪽을 boolean으로 변환. 예를 들어, 흔하게 하는 실수로
messageCount && <p>New messages</p>와 같은 코드를 작성하는 것. 메시지 카운트가 0일 때 아무것도 렌더링하지 않는다고 쉽게 추측할 수 있지만, 실제로는 0 자체를 렌더링함!
📌 react가 무시하는 값들
jsx 안에서 {...}에 넣을 때 null, undefined, false,true는 아에 렌더링 되지 않음.
7️⃣ 리스트 렌더링
화살표 함수는 암시적으로 => 바로 뒤에 식을 반환하기 때문에 return 문이 필요하지 않는다.
const listItems = chemists.map((person) => <li>...</li>); // 암시적 반환!
하지만 => 뒤에 { 중괄호가 오는 경우 return을 명시적으로 작성해야 한다!!
const listItems = chemists.map((person) => {
// 중괄호
return <li>...</li>;
});
=> { 를 표현하는 화살표 함수를 block body를 가지고 있다고 말한다. 이 함수를 사용하면 한 줄 이상의 코드를 작성할 수 있지만 return 문을 반드시 작성해야 한다. 그렇지 않으면 아무것도 반환되지 않는다!
map() 호출 내부의 JSX 엘리먼트에는 항상 key가 필요하다.
짧은 <> </> fragment 구문으로는 key를 전달할 수 없으므로 key를 단일
<div>로 그룹화하거나 약간 더 길고 명시적인<Fragment>문법을 사용을 권장.
📌 key 규칙
- key는 형제 간에 고유해야한다. 하지만 같은 key를 다른 배열의 jsx노드에 동일한 key로 사용해도 된다.
- key는 변경되면 안된다.
- 인덱스를 key로 사용하는 것은 권장하지 않는다.
- key={Math.random()}은 안된다. 매번 DOM이 새로 생성됨.
📌 목록태그
- 비 정렬 목록 태그:
<ul></ul> - 정렬 목록 태그:
<ol></ol> - 목록 항목 태그:
<li></li> - 정의 목록 태그:
<dl></dl> - 정의 태그:
<dt></dt> - 정의 내용 태그:
<dd></dd>
8️⃣ 컴포넌트를 순수하게 유지하기
📌 순수 함수
순수 함수는 자신의 일에 집중한다. 함수가 호출되기 전에 존재했던 어떤 객체나 변수는 변경하지 않는다.
같은 입력, 같은 출력. 같은 입력이 주어지면 항상 같은 결과를 반환한다.
📌 사이드 이펙트
함수가 리턴값 말고 바깥 세상에 영향을 주거나, 바깥 것에 의존하는 행동
React의 렌더링 과정은 항상 순수해야 한다. React에서, 사이드 이펙트는 보통 이벤트 핸들러에 포함시킨다.
export default function Clock({ time }) {
const hours = time.getHours();
if (hours >= 0 && hours <= 6) {
document.getElementById("time").className = "night";
} else {
document.getElementById("time").className = "day";
}
return <h1 id="time"> {time.toLocaleTimeString()} </h1>;
}
이 코드는 순수하지 않다. 왜냐하면 document.getElementById('time')를 사용하여 DOM을 직접 수정하고 있기 때문이다. react가 모르는 DOM 변경은 하지마라!
9️⃣ 트리로서의 UI
📌 렌더 트리
현재 UI의 스냅샷
렌더 트리 : 지금 이 순간 화면을 만들기 위해 React가 들고 있는 컴포넌트 구조, React 컴포넌트 단위로 구성.
📌 모듈 의존성 트리
파일의 관계 지도
모듈 의존성 트리: React 컴포넌트 단위가 아닌 import 된 모듈 단위로 구성.
모듈 의존성 트리의 중요성
- 하나의 번들로 묶을지
- route 단위로 쪼갤지 (코드 스플리팅)
- 동적 import 경계를 어디로 잡을지
- 공통 모듈을 별도 청크로 뺄지
번들러가 분석하는데 큰 도움을 준다.
따라서, React를 잘 이해하려면,
-
렌더 트리를 보고
- 상태 어디에 두는게 좋은지
- 어떤 부분이 자주 리렌더 되는지
- 성능 최적화를 어디에 적용할지
이해해야 하고,
-
모듈 의존성 트리를 보고
- 번들 크기
- 청크 구조
이해하고 튜닝할 수 있어한다.

