1. JSX (JavaScript XML)
개념 요약
- JavaScript XML의 약자로, 페이스북에서 만든 자바스크립트 확장 문법입니다.
- HTML 마크업과 유사하게 작성하여 가독성을 높이며, 내부적으로는 Babel 등을 통해 순수한 자바스크립트(React.createElement) 코드로 컴파일됩니다.
- 공식 문서 참고: 리액트 공식 레거시 문서 - JSX 소개
컴파일 전후 비교 코드
tsx// 1. 우리가 실제로 작성하는 JSX 문법
const element = (
<h1 className="greeting">
Hello, world!
</h1>
);
// 2. Babel에 의해 컴파일된 실제 자바스크립트 형태
const element = React.createElement(
'h1',
{ className: 'greeting' }
);
💡 참고: *.jsx에서 *.tsx로 전환되는 이유
리액트 프로젝트에서 타입스크립트를 도입하면 파일 확장자가 .tsx (TypeScript with JSX)로 변경됩니다. 컴포넌트의 Props와 State에 명확한 타입을 지정하여 컴파일 시점에 에러를 잡아내고 안정성을 높이기 위함입니다.
2. Props & State 개요

- Props: 외부로부터 React Component에 전달되는 읽기 전용 값입니다.
- State: Component 내부적으로 상태가 관리되는 동적인 값입니다.
- 렌더링 조건: Props와 State가 변경이 되면 React Component는 Render 함수를 실행하여 화면을 새롭게 그립니다.
3. Props 예제 (클래스형 vs 함수형)
요청하신 핵심 주석들을 명확하게 매칭한 Props 기본 예제 코드입니다.
tsximport React from 'react';
// ==========================================
// 1. 클래스형 컴포넌트 Props 예제
// ==========================================
interface IClassProps {
contents: string;
}
// React.Component는 두개의 generic을 가진다 첫번째는 props, 두번째는 state이다.
// 여기서 props의 Type은 contents라는 property를 가진 객체이다.
class ClassPropsComponent extends React.Component<IClassProps, {}> {
render() {
return (
<div>
{/* props는 this로 접근가능하다 */}
<p>클래스형 Props 결과: {this.props.contents}</p>
</div>
);
}
}
// ==========================================
// 2. 함수형 컴포넌트 Props 예제
// ==========================================
interface IFuncProps {
contents: string;
}
// React.FC는 functionComponent로 하나의 generic을 가지는데 props이다.
// 함수 컴포넌트의 인자 값으로 props가 전달된다.
const FuncPropsComponent: React.FC<IFuncProps> = (props) => {
return (
<div>
<p>함수형 Props 결과: {props.contents}</p>
</div>
);
};
// 메인 App 컴포넌트에서 호출
export default function App() {
return (
<div>
<ClassPropsComponent contents="This is class component." />
<FuncPropsComponent contents="This is function component." />
</div>
);
}
4. Class형 State 예제
직접 변경(Mutation)을 피하고 불변성(Immutable)을 지켜야 하는 클래스형 상태 관리 예제입니다.
tsximport React, { Component } from 'react';
// props를 정의한 interface
interface IProps {
contents: string;
clickHandler: () => void;
}
// Child Component는 iProps type의 props를 전달 받는다.
// h3를 클릭했을때 실행되는 핸들러 함수는 props의 clickHandler이고 h3 innerText는 props의 contents이다.
class ChildComponent extends Component<IProps> {
render() {
return (
<h3 onClick={this.props.clickHandler} style={{ cursor: 'pointer' }}>
{this.props.contents}
</h3>
);
}
}
// state를 정의한 interface
interface IState {
title: string;
}
export default class ClassStateExample extends Component<{}, IState> {
// class의 property로 state를 선언함
state: IState = {
title: 'Click Me!'
};
changeTitle = () => {
// setState로 state값을 변경함
// 직접 변경하면 render 함수가 실행되지 않음
// reference type일 경우 주소 값을 변경해줘야 바뀐 것으로 판단함(immutable)
this.setState({ title: 'Title changed' });
};
render() {
return (
<div style={{ padding: '20px' }}>
{/* state도 this로 접근가능함 */}
<h2>{this.state.title}</h2>
<ChildComponent
contents="This is function component."
clickHandler={this.changeTitle}
/>
</div>
);
}
}
🖥️ 실행 결과 시각화 (동작 흐름)

5. 함수형 Hook을 사용한 State 예제 (배열 데이터 추가)
원시 타입이 아닌 배열(List) 상태를 다룰 때 불변성을 유지하는 훅(Hook) 예제입니다.
tsximport React, { useState } from 'react';
interface IDataItem {
id: number;
name: string;
}
// props는 id와 name을 속성으로 가지는 iProps객체의 배열이 data 속성의 값인 객체
interface IProps {
data: IDataItem[];
}
const ListComponent: React.FC<IProps> = ({ data }) => {
return (
<ul>
{/* props의 data속성의 배열을 <li> 태그로 만듬 */}
{data.map((item) => (
// react 내부적으로 사용되는 key 속성, unique한 값이 들어가야 됨
<li key={item.id}>{item.name}</li>
))}
</ul>
);
};
export default function FunctionStateExample() {
// useState hook을 사용해서 함수 컴포넌트에서 state사용
// useState의 인자는 초기 state값이며 배열을 리턴한다.
// 배열의 첫번째 인덱스는 state 변수이며 두번째 인덱스는 state변수에 값을 설정하는 함수이다. -> this.setState와 같다
const [people, setPeople] = useState<IDataItem[]>([
{ id: 1, name: '문재인' },
{ id: 2, name: '김정은' },
{ id: 3, name: '트럼프' },
{ id: 4, name: '아베' }
]);
const handleAdd = () => {
// immutable, list 배열을 복사해서 새로운 배열을 만듬
const nextPeople = [...people];
// 새로운 배열에 item을 추가함
nextPeople.push({ id: Date.now(), name: '아베' });
// state에 등록함. render 실행됨
setPeople(nextPeople);
};
return (
<div style={{ padding: '20px' }}>
<ListComponent data={people} />
<button onClick={handleAdd}>추가버튼</button>
</div>
);
}
🖥️ 실행 결과

6. 자식 컴포넌트에서 부모 컴포넌트의 State 변경
리액트는 단방향 데이터 흐름을 가집니다. 자식이 부모의 상태를 바꾸려면, 부모가 상태 변경 함수를 Props로 내려주어야 합니다.
import React, { useState } from 'react';
interface IChildProps {
onNumberChange: () => void;
onLangChange: () => void;
}
const ChildButton: React.FC<IChildProps> = ({ onNumberChange, onLangChange }) => {
return (
<div>
{/* 자식 컴포넌트의 button을 클릭했을때 핸들러는 부모에게서 전달 받은 handler함수를 할당. */}
<button onClick={onNumberChange}>랜덤버튼</button>
<button onClick={onLangChange}>change Language 버튼</button>
</div>
);
};
export default function ParentStateControl() {
const [num, setNum] = useState<number>(0.47641242525235);
const [lang, setLang] = useState<string>('KO');
// 자식 컴포넌트에게 props로 전달될 함수
// 이 함수가 실행되면 부모의 state를 변경한다.
const handleRandom = () => {
setNum(Math.random());
};
const handleLang = () => {
setLang(lang === 'KO' ? 'EN' : 'KO');
};
return (
<div style={{ padding: '20px' }}>
<p>숫자: {num}</p>
<p>언어: {lang}</p>
<hr />
<ChildButton onNumberChange={handleRandom} onLangChange={handleLang} />
</div>
);
}
7. 다중 컴포넌트 환경에서 Props와 State 전달 (Prop Drilling)
컴포넌트가 깊어질 때(1단계 → 2단계 → 3단계) 데이터를 전달하고 올려받는 고전적인 방식과 그 한계점을 보여주는 구조입니다.
import React, { useState } from 'react';
// =======================================================
// 구조 A: 부모(Component1) -> 자식(Component2) -> 손자(Component3) 데이터 전달
// =======================================================
interface IComp3Props {
message: string;
}
function Component3({ message }: IComp3Props) {
// component 1에서 전달받은 message를 표시
return <div style={{ border: '1px dashed red', padding: '10px' }}>Component 3 수신 메시지: {message}</div>;
}
function Component2(props: IComp3Props) {
return (
<div style={{ border: '1px dashed blue', padding: '10px', margin: '10px 0' }}>
<h4>Component 2</h4>
{/* Component 3에 props를 전달하기 위해 spread연산자를 이용해 그대로 전달. */}
{/* 중간에 Component가 추가되거나 props가 추가 되면 값을 전달해주는 작업이 필요함. */}
<Component3 {...props} />
</div>
);
}
// =======================================================
// 구조 B: 손자(Component3)에서 부모(Component1)의 State를 변경하는 역방향 흐름
// =======================================================
interface IReverseProps {
printMessage: () => void;
}
function Component3Bottom({ printMessage }: IReverseProps) {
return (
<div>
{/* button을 클릭하면 props로 전달받은 printMessage함수를 실행 */}
<button onClick={printMessage}>Component3에서 부모 변경 버튼</button>
</div>
);
}
function Component2Bottom({ printMessage }: IReverseProps) {
return (
<div style={{ border: '1px dashed green', padding: '10px', margin: '10px 0' }}>
<h4>Component 2 (하단 부)</h4>
{/* props전달: 중간에 Component가 추가되거나 props가 추가 되면 값을 전달해주는 작업이 필요함 */}
<Component2BottomChild printMessage={printMessage} />
</div>
);
}
// 가독성을 위한 임의의 징검다리 컴포넌트 명칭 지정
const Component2BottomChild = Component3Bottom;
// =======================================================
// 최상위 메인 조율 컴포넌트 (Component 1)
// =======================================================
export default function MultiComponentExample() {
// 자식에게 전달할 props를 state로 등록함
// state를 변경하면 props가 변경되어 자식들이 render 됨
const [msg, setMsg] = useState<string>('초기 메시지');
const [bottomText, setBottomText] = useState<string>('바뀌기 전 텍스트');
// Component3에서 이 함수가 실행되어 state를 변경하여 Text를 변경
const handleChangeText = () => {
setBottomText('Component3에 의해 변경 완료!');
};
return (
<div style={{ padding: '20px', border: '2px solid black' }}>
<h2>Component 1 (최상위 부모)</h2>
<p>하단 텍스트 상태 값: <strong>{bottomText}</strong></p>
<button onClick={() => setMsg('Component 1에서 보낸 새로운 메시지!')}>
Component 3의 Text 변경하기 (상향 전송 테스트용)
</button>
<hr />
{/* 부모 -> 자식 전송 라인 */}
<Component2 message={msg} />
{/* 자식 -> 부모 트리거 라인 */}
{/* Component2에게 자신의 state를 변경해줄 함수를 전달 */}
<Component2Bottom printMessage={handleChangeText} />
</div>
);
}
'Front-end > React' 카테고리의 다른 글
| Zustand란? React 전역 상태 관리 쉽게 이해하기 (0) | 2026.07.02 |
|---|---|
| React Router, Rest 호출(Axios) (0) | 2026.07.02 |
| [React] 리액트 컴포넌트 생명주기(Lifecycle) 총정리: 클래스형부터 useEffect 훅까지 (0) | 2026.07.02 |
| [React] 리액트 Basic (0) | 2026.07.02 |
| [React] React란 React Overview (1) | 2026.07.02 |