일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- 인텔리제이
- pdfmake
- HttpSession
- 리액트오류
- db
- 구글
- Login
- @Query
- 워드프레스
- @Controller
- useEffect
- GA4
- useContext
- firebase
- 구글알고리즘
- @Entity
- post
- @Repository
- 데이터베이스
- set
- 구글애널리틱스
- JPA
- GET
- Thymeleaf
- ussstate
- SEO
- router
- ChatGPT
- Polylang
- 플러그인
- Today
- Total
개발천재
[ReactJS] JSX와 TSX의 차이 본문
JSX와 TSX는 모두 React에서 UI를 만들 때 사용하는 문법이지만, TSX는 타입을 명확히 관리할 수 있는 TypeScript 기반이라는 차이가 있다. 초반에는 JSX로 시작할 수 있지만, 프로젝트가 커지거나 팀과 함께 작업한다면 TSX로 전환하는 것이 더 안정적이다.
구분 | .jsx | .tsx |
언어 | JavaScript + JSX | TypeScript + JSX |
타입 사용 | 타입 사용 불가 | 타입 명시 가능 |
컴파일러 | Babel 등 JS 컴파일러 | TypeScript 컴파일러 |
React 문법 | JSX 문법 사용 | JSX 문법 + 타입 정의 사용 |
JSX(JavaScript XML)
JSX는 JavaScript XML의 줄임말로, 자바스크립트 안에 HTML 같은 코드를 쓸 수 있게 해주는 문법이다. JSX는 브라우저가 직접 이해할 수 없기 때문에 Babel 같은 도구가 JavaScript로 변환해준다.
App.jsx
jsx는 타입 검사 없이 실행된다. 버그가 런타임에서야 발견될 수도 있다.
function Hello({ name }) {
return <div>Hello, {name}!</div>;
}
TSX(TypeScript XML)
TSX는 TypeScript + JSX를 의미한다. JSX 문법을 쓰면서도 TypeScript의 타입 시스템을 함께 사용할 수 있게 해주는 확장자이다.
TypeScript를 프로젝트에서 사용하는 경우엔 반드시 .tsx를 써야 하고, JSX 문법이 없는 TypeScript 파일은 .ts를 쓰면 된다.
App.tsx
tsx에서는 name이 string 타입이어야 한다는 걸 컴파일러가 체크해준다. 컴파일 단게에서 잘못된 타입을 미리 잡아주는게 큰 장점이다.
type HelloProps = {
name: string;
};
function Hello({ name }: HelloProps) {
return <div>Hello, {name}!</div>;
}
TSX를 써야하는 경우
- 프로젝트에서 TypeScript를 사용하는 경우
- 팀 작업 중 실수 방지가 중요한 경우
- 결제 시스템, 회원 정보 등 정확한 데이터 구조가 필요한 경우
특히, 실무 프로젝트나 유지보수가 필요한 서비스, 금융, 결제 같은 프로젝트는에서는 무조건 TSX를 사용하는 것을 권장한다.
TSX에서 자주 사용하는 문법
type 또는 interface – Props와 State 타입 정의
React 컴포넌트에 데이터를 전달할 때 props의 타입을 지정해준다.
type이나 interface 모두 사용 가능하지만, interface는 확장이 가능해 재사용에 유리하다. 복잡한 구조나 extends가 필요하면 interface를, 단순한 구조엔 type을 많이 사용한다.
type UserProps = {
name: string;
age: number;
};
function User({ name, age }: UserProps) {
return <p>{name}은 {age}살입니다.</p>;
}
useState<Type>() – 상태에 타입 지정
React의 useState 훅은 기본적으로 타입 추론을 해주지만, 명시적으로 타입을 지정하면 더 안정적이다.
제네릭을 사용하여 useState()처럼 타입을 넣어준다.
const [count, setCount] = useState<number>(0);
const [username, setUsername] = useState<string>('');
const [items, setItems] = useState<string[]>([]);
특히 초기값이 null일 수 있을 때는 string | null 같은 유니언 타입도 자주 사용된다.
const [selectedItem, setSelectedItem] = useState<string | null>(null);
useRef<Type>() – DOM 또는 값을 참조할 때
useRef는 HTML 요소나 특정 값을 참조할 때 사용하는 훅이다. 이때도 타입을 명확하게 지정해줄 수 있어야 한다.
null 초기값이 들어가므로 | null을 포함하는 것이 일반적이다.
const inputRef = useRef<HTMLInputElement>(null);
// 사용 시:
<input ref={inputRef} />
DOM뿐만 아니라 일반 값의 저장소로도 사용한다.
const timerId = useRef<number | null>(null);
React.FC<Props> – 컴포넌트에 기본 타입 적용
React의 함수형 컴포넌트에 타입을 적용할 때 React.FC (또는 React.FunctionComponent)를 사용하면 편리하다.
단, React.FC에는 children이 자동으로 포함되므로, children이 없는 경우는 명시적으로 안 쓰기도 한다.
interface GreetingProps {
name: string;
}
const Greeting: React.FC<GreetingProps> = ({ name }) => {
return <h1>Hello, {name}!</h1>;
};
제네릭(Generic) – 재사용 가능한 컴포넌트 작성
제네릭은 여러 타입에 대해 유연하게 대응할 수 있게 해주는 기능이다. 리스트, 폼, 셀렉트박스 등 재사용 가능한 컴포넌트를 만들 때 자주 사용한다.
T는 임의의 타입을 의미하고, 사용하는 쪽에서 실제 타입이 결정된다. 복잡한 UI 구성에서 컴포넌트 재사용성을 극대화할 수 있다.
type ListProps<T> = {
items: T[];
renderItem: (item: T) => React.ReactNode;
};
function List<T>({ items, renderItem }: ListProps<T>) {
return <ul>{items.map(renderItem)}</ul>;
}
// 사용 예
<List items={['apple', 'banana']} renderItem={(item) => <li>{item}</li>} />
React 프로젝트에서 TypeScript 시작하기
아래의 명령어를 터미널에 입력한다.
npx create-react-app my-app --template typescript
기존 React 프로젝트에 TypeScript를 적용하려면 다음 명령어를 실행한다.
npm install --save typescript @types/react @types/react-dom
TSX 예시
기본 함수형 컴포넌트(Props 타입 지정)
type GreetingProps = {
name: string;
age?: number; // 선택적 props
};
const Greeting: React.FC<GreetingProps> = ({ name, age }) => {
return (
<div>
<p>Hello, {name}!</p>
{age && <p>You are {age} years old.</p>}
</div>
);
};
useState에 타입 지정
import { useState } from "react";
const Counter = () => {
const [count, setCount] = useState<number>(0);
return (
<button onClick={() => setCount(count + 1)}>
Count: {count}
</button>
);
};
이벤트에 타입 지정
const Form = () => {
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
console.log("Form submitted");
};
return (
<form onSubmit={handleSubmit}>
<button type="submit">Submit</button>
</form>
);
};
컴포넌트에 Children 사용하기
type CardProps = {
title: string;
children: React.ReactNode;
};
const Card = ({ title, children }: CardProps) => (
<div className="card">
<h2>{title}</h2>
<div>{children}</div>
</div>
);
JSX 안에서 조건부 랜더링 + map
type Todo = {
id: number;
text: string;
completed: boolean;
};
type TodoListProps = {
todos: Todo[];
};
const TodoList = ({ todos }: TodoListProps) => (
<ul>
{todos.map((todo) => (
<li key={todo.id}>
{todo.text} {todo.completed ? "✅" : "❌"}
</li>
))}
</ul>
);
컴포넌트에 defaultProps 적용
type ButtonProps = {
label: string;
color?: string;
};
const Button = ({ label, color = "blue" }: ButtonProps) => (
<button style={{ backgroundColor: color }}>{label}</button>
);
'개발 준비 > ReactJS' 카테고리의 다른 글
[ReactJS] DOM 직접 제어하기, useRef, forwordRef, useImperativeHandle (0) | 2025.05.15 |
---|---|
[ReactJS] PDF 다운로드 기능 구현하기, jsPDF + html2canvas (0) | 2025.05.13 |
[ReactJS] CRA와 Vite 프로젝트, 마이그레이션하기 (0) | 2025.05.12 |
[ReactJS] npm error Missing script: "start", react-scripts@5.0.1 (0) | 2025.05.09 |
[ReactJS] 원자 단위로 상태 관리하기, Jotai (0) | 2025.04.30 |