-
React 는 사용자 인터페이스(UI)를 렌더링하기 위한 JS 라이브러리
- 버튼, 텍스트, 이미지와 같은 작은 요소 로 구성
- React를 통해 작은 요소들을 재사용 가능하고 중첩할 수 있는 컴포넌트로 조합가능
🧩 Component
React 애플리케이션은 컴포넌트라고 불리는 독립된 UI 조각들로 이루어짐
React 컴포넌트는 마크업을 얹을 수 있는 JavaScript 함수
- 마크업, CSS, Javascript를 앱의 재사용 가능한 UI 요소인 사용자 정의 컴포넌트로 조합
↗️ 컴포넌트 import / export
컴포넌트의 가장 큰 장점은 재사용성이다.
- 컴포넌트를 조합해 또 다른 컴포넌트를 만들 수 있다.
컴포넌트를 이렇게 여러 번 중첩하면 다른 파일로 분리해야 하는 시점이 있다.
- 분리를 하여 파일을 더 찾기 쉽고 재사용하기 편리
📍 export
- 함수 컴포넌트를 export
- default 또는 named export 방식을 사용
function Profile() { return ( <img src="test.jpg" alt="test" /> ); } export default function Gallery() { return ( <section> <Profile /> <Profile /> <Profile /> </section> ); }- default 방식으로 export
📍 import
- 컴포넌트를 사용할 파일에서 import
- default 또는 named 로 import
import Gallery from './Gallery.js'; export default function App() { return ( <Gallery /> ); }- default 방식으로 import
✅ 한 파일에서 여러번 import, export 하는 방법
- default 키워드 없이 export
- named export
export function Profile() {} ---- import { Profile } from './Gallery.js';🤖 함수 정의
function Profile() { .. }⚠️ 주의 사항
- React 컴포넌트는 일반적인 Javascript 함수이지만 이름은 대문자로 시작해야 한다.
- 그렇지 않으면 작동하지 않음
📌 마크업 추가
return <img src="test.jpg" alt="test" />;<img /> 는 HTML 같아 보이지만 실제로는 JS이다.
- JSX라고 함
return ( <div> <img src="test.jpg" alt="test" /> </div> );- 마크업이 return 키워드와 같은 라인에 있지 않은 경우 괄호로 묶는다.
🌐브라우저에 표시되는 내용
export default function Gallery() { return ( <section> <Profile /> <Profile /> <Profile /> </section> ); } ----- ⬇️ 브라우저에 표시 <section> <img src="https://test.jpg" alt="test" /> <img src="https://test.jpg" alt="test" /> <img src="https://test.jpg" alt="test" /> </section>✅ 대소문자에 주의
- <section> 은 소문자이므로 React는 HTML태그를 가리킨다고 이해
- <Profile /> 은 대문자 P로 시작하므로 React는 Profile이라는 컴포넌트를 사용하고자 한다고 이해
📖 JSX 로 마크업 작성하기
- JSX와 HTML의 차이점
- JSX로 정보를 보여주는 방법
JSX는 Javascript를 확장한 문법
- JS 파일을 HTML과 비슷하게 작성할 수 있게 해준다.
🔍 React에서 마크업과 렌더링 로직을 같이 사용하는 이유
이전까지 HTML에 내용, CSS에 디자인, JS로 로직을 작성
- 분리된 파일로 관리
웹이 더욱 인터랙티브해지면서 로직이 내용을 결정하는 경우가 많아져 JavaScript가 HTML을 담당하게 됨
- React에서 렌더링 로직과 마크업이 같은 위치에 있게 된 이유
🤖 React 컴포넌트
- React 가 브라우저에 마크업을 렌더링할 수 있는 JS 함수
👍 JSX는 HTML과 비슷해보이지만 더 엄격하고 동적으로 표현할 수 있도록 해준다.
↪️ HTML 을 JSX로 표현해보기
<h1>Todos</h1> <img src="test.jpg" class="photo" > <ul> <li>li1 <li>li2 <li>li3 </ul>- 위 코드를 구현하기 위해 알아야할 JSX 규칙이 존재
🚀 규칙 1 - 하나의 루트 엘리먼트로 반환
한 컴포넌트에서 여러 엘리먼트를 반환하기 위해서는 하나의 부모 태그로 감싸야 한다.
function Test() { return ( <h1> hello </h1> <img src="" alt="" className="photo" /> <ul> <li></li> <li></li> <li></li> </ul> ); } ----- ❌ JSX expressions must have one parent element.function Test() { return ( <> <h1> hello </h1> <img src="" alt="" className="photo" /> <ul> <li></li> <li></li> <li></li> </ul> </> ); }- Fragment : <> </>
🤔 왜 여러 JSX 태그를 하나로 감싸줘야 할까??
💡 JSX는 내부적으로 일반 JS 객체로 변환되기 때문에 하나의 배열로 감싸지 않은 하나의 함수에서는 두 개의 객체를 반환할 수 없다.
따라서 다른 태그나 Fragment로 감싸지 않으면 두 개의 JSX 태그를 반환할 수 없음.
🖥️ 실제 Babel 을 통해서 변환된 모습을 확인해보자
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; function Test() { return /*#__PURE__*/_jsxs(_Fragment, { children: [/*#__PURE__*/_jsx("h1", { children: " Hedy " }), /*#__PURE__*/_jsx("img", { src: "", alt: "", className: "photo" }), /*#__PURE__*/_jsxs("ul", { children: [/*#__PURE__*/_jsx("li", {}), /*#__PURE__*/_jsx("li", {}), /*#__PURE__*/_jsx("li", {})] })] }); }- 여러 JSX를 children 배열로 감싸 Fragment로 반환
🚀 규칙 2 - 모든 태그는 닫아주기
JSX에서는 태그를 명시적으로 닫아야한다.
<img>처럼 자체적으로 닫아주는 태그는 반드시<img />형태로 작성
🚀 규칙 3 - camel Case
JSX는 JS로 바뀌고 JSX에 작성된 어트리뷰트(속성)는 JS 객체의 key가 된다.
컴포넌트에 어트리뷰틀르 변수로 읽고 싶을 경우 제한이 존재
- JS 변수명에 대시를 포함하거나 class 와 같은 예약어를 사용할 수 없다.
💡 따라서 React에서 HTML, SVG 어트리뷰트 대부분이 캐멀 케이스로 작성
- stroke-width ⇒ strokeWidth
- class ⇒ className
🧩 문자열 어트리뷰트
“”로 전달 / 동적 - {}‘’나“”로 문자열 어트리뷰트를 JSX에 전달
<img src="ddd" />동적으로 지정하기 위해서는 {} 를 사용
const image = ""; <img src={image} />📌 {} 로 Javascript 사용
- 중괄호 사이에 JS를 사용할 수 있다.
export default function TodoList() { const name = 'beomsic'; return ( <h1>{name}'s To Do List</h1> ); }↖️ {{ }} 으로 객체를 전달
export default function TodoList() { return ( <ul style={{ backgroundColor: 'black', color: 'pink' }}> <li>Improve the videophone</li> </ul> ); }- 객체를 전달하려면 다른 괄호를 이용해서 객체를 감싼다.
🤖 컴포넌트에 props 전달하기
React 컴포넌트는 props를 이용해 서로 통신
- 부모 컴포넌트는 props를 통해 정보를 자식 컴포넌트에게 전달
- 객체, 배열, 함수를 포함한 모든 JS 값을 전달할 수 있다.
1️⃣ 자식 컴포넌트에 props 전달
export default function Profile() { return ( <Avatar person={{ name: 'Lin Lanying', imageId: '1bX5QH6' }} size={100} /> ); }- person 객체, size (숫자)
❗ Avatar 컴포넌트 내에서 props를 읽을 수 있다.
2️⃣ 자식 컴포넌트 내부에서 props 읽기
function Avatar({ person, size }) { // 구조 분해 할당 // 전달된 props 사용 가능 } --- function Avatar(props) { let person = props.person; let size = props.size; }props에 기본값을 지정할 수도 있다.
function Avatar({ person, size = 10 }) { // 전달된 props 사용 가능 }🧩 JSX spread 문법으로 props 전달
- 부모 컴포넌트에서 자식 컴포넌트로 모든 props를 전달해야 할 경우
- props를 하나하나 설정을 해주게 된다면 반복되는 코드가 발생하게 될 것이다.
💡 spread를 통해 해결
function Profile({ person, size, ....}) { return ( <div className="card"> <Avatar person={person} size={size} ... /> </div> ) } ---- spread 사용 function Profile(props) { return ( <div className="card"> <Avatar {...props} /> </div> ) }⚠️ 이런 spread 가 많이 사용된다는 것은 문제가 있는 것!!
- 컴포넌트를 분리해야 함을 나타낸다.
⬆️ 자식을 부모에게 JSX로 전달
<Card> <Avator /> </Card>- 컴포넌트를 중첩
JSX 태그내에서 콘텐츠를 중첩하게 되면 부모 컴포넌트는 해당 콘텐츠를 children이라는 props로 받게된다.
import Avatar from './Avatar.js'; function Card({ children }) { return ( <div className="card"> {children} </div> ); } export default function Profile() { return ( <Card> <Avatar size={100} person={{ name: 'beomsic', }} /> </Card> ); }여기서 Card 컴포넌트는 Avatar 컴포넌트로 설정된 children prop를 받아서 이를 div 에 렌더링한다.
✅ 조건부 렌더링
if,&&,?: 와 같은 자바스크립트 문법을 사용해 조건부로 JSX를 렌더링조건에 따라 다른 JSX를 반환하는 방법
- prop 값을 통해 다른 JSX를 반환
function Item({isPacked, name}) { if (isPacked) return <li> ✅ </li>; return <li> ❌ </li>; } export default function PackingList() { return ( <> <Item isPacked={true} name="item1" /> <Item isPacked={false} name="item2" /> </> ) }✔️ 삼항 조건 연산자
자바스크립트의 조건 연산자를 사용
if (isPacked) { return <li className="item">{name} ✅</li>; } return <li className="item">{name}</li>; --- 위 코드를 삼항 조건 연산자를 이용해서 간단히 수정 return ( <li className="item"> {isPacked ? name + ' ✅' : name} </li> )📌 논리 AND 연산자 (
&&)&&React 컴포넌트에서는 조건이 참일 때 일부 JSX를 렌더링 하거나 그렇지 않으면 아무것도 렌더링하지 않을 때를 나타낼 수 있다.
- && 을 이용
return ( <li className="item"> {name} {isPacked && '✅'} </li> )- isPacked 가 true라면 체크 표시를 렌더링하고 그렇지 않으면 아무것도 렌더링을 하지 않는다는 의미
⚠️ && 왼쪽에는 boolean 값을 주어야 한다.
📂 리스트 렌더링
데이터들에서 유사한 컴포넌트를 여러 개 표시하기 위한 방법
- JS 배열 메서드를 사용
📌 배열을 데이터로 렌더링
<ul> <li>Creola Katherine Johnson: mathematician</li> <li>Mario José Molina-Pasquel Henríquez: chemist</li> <li>Mohammad Abdus Salam: physicist</li> <li>Percy Lavon Julian: chemist</li> <li>Subrahmanyan Chandrasekhar: astrophysicist</li> </ul>- 리스트 항목은 데이터 값만 다르다.
🤔 다른 데이터들을 통해서 동일한 컴포넌트의 여러 인스턴스를 표시해야 한다면??
💡 자바스크립트 객체, 배열에 저장하고 map() filter() 메서드를 사용해 컴포넌트 리스트를 렌더링
1️⃣ 데이터를 배열로 표시
const people = [ 'Creola Katherine Johnson: mathematician', 'Mario José Molina-Pasquel Henríquez: chemist', 'Mohammad Abdus Salam: physicist', 'Percy Lavon Julian: chemist', 'Subrahmanyan Chandrasekhar: astrophysicist' ];2️⃣ people 배열을 map()을 이용해서 JSX 노드 배열로 매핑 (listItems)
const listItems = people.map(person => <li>{person}</li>);3️⃣ ul 로 매핑한 컴포넌트의 listItems 반환
return <ul>{listItems}</ul>;✔️ 최종 코드
const people = [ 'Creola Katherine Johnson: mathematician', 'Mario José Molina-Pasquel Henríquez: chemist', 'Mohammad Abdus Salam: physicist', 'Percy Lavon Julian: chemist', 'Subrahmanyan Chandrasekhar: astrophysicist' ]; export default function List() { const listItems = people.map(person => <li>{person}</li> ); return <ul>{listItems}</ul>; }⚠️ Warning: Each child in a list should have a unique “key” prop.
위 코드에서 위와 같은 에러가 발생!!
📌 필터링 하기
filter() 메서드를 이용
const people = [{ id: 0, name: 'Creola Katherine Johnson', profession: 'mathematician', }, { id: 1, name: 'Mario José Molina-Pasquel Henríquez', profession: 'chemist', }, { id: 2, name: 'Mohammad Abdus Salam', profession: 'physicist', }, { id: 3, name: 'Percy Lavon Julian', profession: 'chemist', }, { id: 4, name: 'Subrahmanyan Chandrasekhar', profession: 'astrophysicist', }]; const chemists = people.filter(person => person.profession === 'chemist' );🔑 Key를 사용해서 리스트 순서대로 유지
⚠️ Warning: Each child in a list should have a unique “key” prop.
위에서 발생했던 에러를 해결해보자.
각 배열 항목에 대해서 고유하게 식별할 수 있는 문자열이나 숫자를 key로 지정을 해주어야 한다! ⭐
key를 통해 각 컴포넌트가 어떤 배열 항목에 해당하는지 React에게 알려주어 나중에 일치하도록 한다.
배열이 정렬등 이동하거나 삽입되거나 삭제될 경우 중요
- Key를 잘 사용하면 React가 어떤 일이 일어났는지 추론하고 DOM 트리를 업데이트하는데 도움이 된다.
import { people } from './data.js'; import { getImageUrl } from './utils.js'; export default function List() { const listItems = people.map(person => <li key={person.id}> ... </li> ); return <ul>{listItems}</ul>; }🧩 Key 값
데이터 항목마다 다른 key 값을 제공해주어야 합니다.
- 데이터베이스의 데이터 (데이터베이스의 key, ID)
- 로컬에서 생성된 데이터일 경우
- 증분되는 번호나
- crypto.randomUUID()
- uuid 패키지
☑️ Key 규칙
- key는 형제간에 고유해야 한다.
- 다른 배열의 JSX 노드에는 동일한 key로 해도 상관없다.
- key는 변경되어서는 안된다.
- 목적에 어긋나는 행위
- 렌더링중 key를 생성하면 안된다!!
🌈 컴포넌트 순수하게 유지하기
순수 함수는 오직 연산만을 수행
컴포넌트를 엄격하게 순수함수로 작성하면 코드가 점차 커지더라도 예상밖의 동작이나 버그를 피할 수 있다.
📍순수 함수
- 함수가 호출되기전 존재했던 어떤 객체나 변수가 변경되지 않음
- 같은 입력이 주어지면 같은 결과를 반환
🤖 리액트는 모든 컴포넌트가 순수 함수일것이라 가정
- React 컴포넌트에 같은 입력이 주어지면 같은 JSX를 반환한다
⚠️ 사이드 이펙트
React의 렌더링 과정은 순수해야하고 컴포넌트는 JSX만 반환해야 했으며 렌더링 이전에 존재했던 객체나 변수를 변경해서는 안된다.
let guest = 0; function Cup() { // 나쁜 지점: 이미 존재했던 변수를 변경하고 있습니다! guest = guest + 1; return <h2>Tea cup for guest #{guest}</h2>; } export default function TeaSet() { return ( <> <Cup /> </> ); }- 컴포넌트의 밖에 선언된 Guest라는 변수를 읽고 수정
📌 프로퍼티로 변수를 넘겨 해결
function Cup({ guest }) { return <h2>Tea cup for guest #{guest}</h2>; } export default function TeaSet() { return ( <> <Cup guest={1} /> <Cup guest={3} /> </> ); }💡 정리
컴포넌트는 순수해야 한다.
1️⃣ 렌더링 전에 존재했던 객체나 변수를 변경하지 않고 자신이 맡은 일을 한다.
2️⃣ 같은 입력이 들어온 경우 항상 같은 JSX 결과를 반환해야 한다.
🌴 트리로 UI 이해하기
React 앱은 중첩된 많은 컴포넌트로 구성되어 있다.
- React는 어떻게 앱의 컴포넌트 구조를 추적하나?
🌴 트리로서의 UI
UI를 트리로 모델링
트리는 component와 UI 사이의 관계 모델로 UI는 종종 트리 구조를 사용해 표현된다.

- ex: 브라우저는 HTML (DOM)과 CSS(CSSOM)를 모델링하기 위해 트리구조를 사용
React도 역시 컴포넌트 간의 관계를 관리하고 모델링하기 위해 트리 구조를 사용
⭐ 렌더 트리
컴포넌트의 주요 특징은 다른 컴포넌트의 컴포넌트를 구성하는 것이다.
- 컴포넌트 중첩
컴포넌트를 중첩시 부모 컴포넌트와 자식 컴포넌트의 개념이 생기고 각 부모 컴포넌트는 다른 컴포넌트의 자식이 될 수 있다.
이런 관계를 React 앱을 렌더링 할 때 렌더 트리라고 알려진 트리로 모델링할 수 있다.
import FancyText from './FancyText'; import InspirationGenerator from './InspirationGenerator'; import Copyright from './Copyright'; export default function App() { return ( <> <FancyText title text="Get Inspired App" /> <InspirationGenerator> <Copyright year={2004} /> </InspirationGenerator> </> ); }위 코드를 렌더 트리로 나타내면 아래와 같다.

React 앱에서 최상위 컴포넌트와 리프 컴포넌트가 무엇인지 식별하는데 도움이 된다.
🧩 조건부 렌더링을 하면 Prop 값으로 인해 컴포넌트가 다른 자식 컴포넌트를 렌더링할 수 있다.
🔗 모듈 의존성 트리
트리로 모델링 할 수 있는 다른 관계는 앱의 모듈 의존성이다.
- 컴포넌트를 분리한 후 로직을 별도의 파일로 분리하면 컴포넌트, 함수, 상수를 내보내는 JS 모듈을 만들 수 있다.
각 노드는 모듈, 각 가지는 해당 모듈의 Import 문을 나타낸다.
'FE > React' 카테고리의 다른 글
React의 State 업데이트 큐 (0) 2025.10.23 React 개요 (0) 2025.10.23