1. JSX (JavaScript XML)
JSX는 JavaScript에서 HTML을 작성할 수 있는 문법.
React에서 UI를 선언적으로 표현할 때 사용.
1️⃣ JSX 기본 문법
JSX는 HTML과 유사하지만, JavaScript 표현식을 {} 안에 포함할 수 있습니다.
const name = "희성";
const element = <h1>Hello, {name}!</h1>;
ReactDOM.render(element, document.getElementById("root"));
HTML과 차이점
- class → className 사용
- onclick → onClick (camelCase로 작성)
- JavaScript 코드 사용 시 {} 중괄호로 감싸야 함
2️⃣ JSX에서 속성 사용하기
className (HTML의 class 대신 사용)
const element = <h1 className="title">Hello, JSX!</h1>;
camelCase 속성 표기법
HTML 속성 이름이 camelCase로 변환됨.
const button = <button onClick={() => alert("클릭!")}>Click me</button>;
const input = <input type="text" placeholder="입력하세요" autoFocus />;
3️⃣ JSX에서 {} 중괄호 표현식
JSX 내부에서는 JavaScript 표현식을 {} 안에 사용할 수 있음.
const user = {
name: "희성",
age: 25,
};
const element = <h1>이름: {user.name}, 나이: {user.age}</h1>;
삼항 연산자 사용 가능
const isLoggedIn = true;
const message = <h1>{isLoggedIn ? "환영합니다!" : "로그인하세요."}</h1>;
함수 호출도 가능
const getGreeting = (name) => `Hello, ${name}!`;
const element = <h1>{getGreeting("희성")}</h1>;
4️⃣ JSX에서 조건부 렌더링
&& 연산자 사용
조건이 true일 때만 렌더링함.
const isLoggedIn = true;
const welcomeMessage = (
<div>
<h1>환영합니다!</h1>
{isLoggedIn && <p>로그인 상태입니다.</p>}
</div>
);
isLoggedIn이 true일 때만 <p>로그인 상태입니다.</p>가 렌더링됨.
삼항 연산자 (? :) 사용
삼항 연산자를 사용하면 더 명확한 조건부 렌더링 가능.
const isLoggedIn = false;
const message = (
<h1>{isLoggedIn ? "환영합니다!" : "로그인하세요."}</h1>
);
isLoggedIn === true → "환영합니다!"
isLoggedIn === false → "로그인하세요."
if문을 사용한 렌더링
JSX 내부에서 if문은 직접 사용할 수 없으므로, 함수 밖에서 처리해야 함.
const isLoggedIn = false;
let message;
if (isLoggedIn) {
message = <h1>환영합니다!</h1>;
} else {
message = <h1>로그인하세요.</h1>;
}
const element = <div>{message}</div>;
if문을 JSX 안에서 직접 사용할 수 없기 때문에, JSX 밖에서 변수를 선언하여 처리해야 함.
2. React 컴포넌트
React에서 컴포넌트(Component)는 UI를 구성하는 기본 단위.
1️⃣ 함수형 컴포넌트 vs 클래스형 컴포넌트
함수형 컴포넌트 (Functional Component)
React Hooks(useState, useEffect)를 사용하여 간결하게 상태 관리할 수 있는 최신 방식.
const Greeting = ({ name }) => {
return <h1>안녕하세요, {name}님!</h1>;
};
export default Greeting;
장점
- 코드가 간결하고 직관적
- this를 사용하지 않음
- 성능이 더 좋음
클래스형 컴포넌트 (Class Component)
React의 이전 방식. this.state와 this.setState()를 사용하여 상태를 관리.
import React, { Component } from "react";
class Greeting extends Component {
render() {
return <h1>안녕하세요, {this.props.name}님!</h1>;
}
}
export default Greeting;
❌ 단점
- 코드가 길고 this를 많이 사용해야 함
- 함수형 컴포넌트보다 성능이 약간 느림
결론: Hooks(useState)가 도입된 이후 함수형 컴포넌트 사용을 권장!
2️⃣ Props (속성)
부모 → 자식 컴포넌트로 데이터를 전달할 때 사용.
const Child = ({ name }) => {
return <h1>이름: {name}</h1>;
};
const Parent = () => {
return <Child name="React" />;
};
export default Parent;
Props는 읽기 전용 (불변성 유지됨)
자식 컴포넌트에서 변경할 수 없음
props.children
컴포넌트 내부에 다른 요소를 넣을 수 있음.
const Card = ({ children }) => {
return <div className="card">{children}</div>;
};
const App = () => {
return (
<Card>
<h1>타이틀</h1>
<p>이것은 내용입니다.</p>
</Card>
);
};
export default App;
props.children을 사용하면 컴포넌트 내부에서 전달된 요소를 렌더링할 수 있음.
3️⃣ State (상태)
컴포넌트의 변경 가능한 데이터
→ useState를 사용하여 상태를 관리
useState로 상태 관리
import { useState } from "react";
const Counter = () => {
const [count, setCount] = useState(0); // 초기값 0
return (
<div>
<h1>카운트: {count}</h1>
<button onClick={() => setCount(count + 1)}>증가</button>
</div>
);
};
export default Counter;
useState(초기값) → 상태 변수와 상태 변경 함수 반환
setCount(newValue) → 상태 변경 시 컴포넌트가 다시 렌더링됨
불변성을 유지하면서 상태 변경 (setState)
객체 상태를 변경할 때 새로운 객체를 생성해야 함.
const [user, setUser] = useState({ name: "희성", age: 25 });
const updateUser = () => {
setUser({ ...user, age: 26 }); // 불변성 유지하면서 새로운 객체 생성
};
return (
<div>
<h1>이름: {user.name}, 나이: {user.age}</h1>
<button onClick={updateUser}>나이 증가</button>
</div>
);
객체를 직접 수정하면 안 됨!
user.age = 26; (이렇게 하면 상태 변경이 감지되지 않음)
불변성을 유지하면서 새로운 객체 생성해야 함.
setUser({ ...user, age: 26 });
3. React 이벤트 핸들링 정리
1️⃣ 이벤트 핸들링 (onClick, onChange, onSubmit 등)
React에서는 HTML과 유사한 이벤트를 camelCase로 사용합니다.
onClick 이벤트 (버튼 클릭)
const ButtonComponent = () => {
const handleClick = () => {
alert("버튼이 클릭되었습니다!");
};
return <button onClick={handleClick}>클릭하세요</button>;
};
export default ButtonComponent;
이벤트 핸들러는 함수로 작성하고, onClick={handleClick}처럼 전달해야 함
onClick={handleClick()} → 이렇게 하면 컴포넌트가 렌더링될 때 바로 실행됨
onChange 이벤트 (입력값 변경)
사용자의 입력을 감지하여 state에 저장할 수 있음.
import { useState } from "react";
const InputComponent = () => {
const [text, setText] = useState("");
const handleChange = (event) => {
setText(event.target.value); // 입력값을 상태에 저장
};
return (
<div>
<input type="text" value={text} onChange={handleChange} />
<p>입력한 값: {text}</p>
</div>
);
};
export default InputComponent;
event.target.value → 입력 필드의 값 가져오기
setText() → 상태 변경으로 화면 업데이트
onSubmit 이벤트 (폼 제출)
기본적으로 폼 제출 시 페이지가 새로고침되므로, 이를 preventDefault()로 방지해야 함.
import { useState } from "react";
const FormComponent = () => {
const [name, setName] = useState("");
const handleSubmit = (event) => {
event.preventDefault(); // 기본 이벤트 방지
alert(`제출된 이름: ${name}`);
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
/>
<button type="submit">제출</button>
</form>
);
};
export default FormComponent;
event.preventDefault() → 기본 폼 제출 동작(새로고침) 방지
onChange로 입력값 상태 관리
onSubmit에서 상태값을 활용하여 제출 처리
2️⃣ 이벤트 핸들러에서 setState() 활용
이벤트 발생 시 상태(state)를 변경하면 UI가 자동으로 업데이트됨.
버튼 클릭 시 상태 변경 (setState)
import { useState } from "react";
const Counter = () => {
const [count, setCount] = useState(0);
const handleIncrease = () => {
setCount(count + 1);
};
return (
<div>
<h1>카운트: {count}</h1>
<button onClick={handleIncrease}>증가</button>
</div>
);
};
export default Counter;
setCount(count + 1)을 호출하면 React가 자동으로 다시 렌더링
주의! 상태 변경 시 불변성을 유지해야 함.
const [user, setUser] = useState({ name: "희성", age: 25 });
const updateAge = () => {
setUser({ ...user, age: user.age + 1 }); // 새로운 객체를 생성해야 함
};
user.age++ → 원본을 직접 수정하면 안 됨!
setUser({ ...user, age: user.age + 1 }) → 새로운 객체 생성
3️⃣ preventDefault()로 기본 이벤트 방지
링크 클릭 시 페이지 이동 방지
const LinkComponent = () => {
const handleClick = (event) => {
event.preventDefault();
alert("링크 클릭 방지됨!");
};
return 클릭하면 안 돼요;
};
export default LinkComponent;
event.preventDefault()를 호출하면 링크 이동이 방지됨.
Enter 키 입력 시 기본 동작 방지
const InputPreventEnter = () => {
const handleKeyPress = (event) => {
if (event.key === "Enter") {
event.preventDefault();
alert("Enter 키 입력 방지됨!");
}
};
return <input type="text" onKeyPress={handleKeyPress} />;
};
export default InputPreventEnter;
event.key === "Enter" → Enter 키 감지
event.preventDefault() → 기본 제출 동작 방지
4. React 조건부 렌더링
React에서는 조건에 따라 UI를 변경하는 조건부 렌더링(Conditional Rendering)을 사용할 수 있습니다.
주로 삼항 연산자 (? :), && 연산자, if-else문을 활용.
1️⃣ 삼항 연산자 (condition ? A : B)
조건이 **참(true)**이면 A를, **거짓(false)**이면 B를 렌더링합니다.
const UserGreeting = ({ isLoggedIn }) => {
return <h1>{isLoggedIn ? "환영합니다!" : "로그인해주세요."}</h1>;
};
export default UserGreeting;
isLoggedIn === true → "환영합니다!"
isLoggedIn === false → "로그인해주세요."
삼항 연산자를 사용하면 간결한 코드 작성 가능!
2️⃣ && 연산자 (condition && <Component />)
조건이 **참(true)**일 때만 컴포넌트를 렌더링합니다.
const Notification = ({ hasNewMessages }) => {
return (
<div>
<h1>알림</h1>
{hasNewMessages && <p>새로운 메시지가 있습니다!</p>}
</div>
);
};
export default Notification;
hasNewMessages === true → <p>새로운 메시지가 있습니다!</p> 렌더링
hasNewMessages === false → 아무것도 렌더링되지 않음
3️⃣ if-else를 사용한 조건부 렌더링
JSX 내부에서 if-else 문을 직접 사용할 수 없기 때문에, JSX 외부에서 변수를 선언하여 처리해야 합니다.
const UserStatus = ({ isLoggedIn }) => {
let message;
if (isLoggedIn) {
message = <h1>환영합니다!</h1>;
} else {
message = <h1>로그인해주세요.</h1>;
}
return <div>{message}</div>;
};
export default UserStatus;
장점: 가독성이 좋고, 여러 줄의 JSX를 포함할 때 유용
단점: JSX 내부에서 바로 사용할 수 없음
4️⃣ 즉시 실행 함수 (IIFE)를 사용한 조건부 렌더링
즉시 실행 함수(IIFE)를 사용하면 JSX 내부에서도 if-else를 사용할 수 있습니다.
const UserStatus = ({ isLoggedIn }) => {
return (
<div>
{(() => {
if (isLoggedIn) {
return <h1>환영합니다!</h1>;
} else {
return <h1>로그인해주세요.</h1>;
}
})()}
</div>
);
};
export default UserStatus;
즉시 실행 함수를 사용하면 JSX 내부에서도 if-else를 적용 가능
하지만 가독성이 떨어질 수 있음, 삼항 연산자나 별도의 변수 선언이 더 권장됨.
5. React에서 리스트와 key
React에서 리스트를 렌더링할 때 map()을 사용하며, 각 요소에 key 속성을 부여하는 것이 중요.
1️⃣ 배열을 map()을 사용하여 렌더링
map()을 사용하여 배열의 요소를 React 컴포넌트로 변환할 수 있습니다.
const List = () => {
const fruits = ["🍎 사과", "🍌 바나나", "🍇 포도"];
return (
<ul>
{fruits.map((fruit, index) => (
<li key={index}>{fruit}</li>
))}
</ul>
);
};
export default List;
map()을 사용하여 배열의 각 요소를 <li> 태그로 변환
각 요소에 key 속성 추가 필요! (key={index})
2️⃣ key 속성의 중요성
React에서 key는 리스트의 각 요소를 고유하게 식별하는 역할을 합니다.
key가 필요한 이유
- 렌더링 성능 최적화
→ key가 없으면 React는 매번 모든 요소를 다시 렌더링함.
→ key가 있으면 변경된 요소만 업데이트할 수 있음. - 올바른 요소 식별
→ 리스트가 변경될 때 React가 어떤 요소를 추가, 변경, 삭제해야 하는지 알 수 있음.
key 없이 렌더링하는 경우 (비효율적)
const List = () => {
const items = ["🍕 피자", "🍔 햄버거", "🍣 초밥"];
return (
<ul>
{items.map((item) => (
<li>{item}</li> // ❌ key가 없음 → 경고 발생!
))}
</ul>
);
};
🚨 Warning: Each child in a list should have a unique "key" prop.
고유한 key를 추가하면 해결됨!
3️⃣ 고유한 key 부여하는 방법
1. 데이터에 고유한 ID가 있는 경우 (권장)
const List = () => {
const users = [
{ id: 1, name: "희성" },
{ id: 2, name: "지민" },
{ id: 3, name: "태형" }
];
return (
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li> // ✅ 고유한 id 사용 (권장)
))}
</ul>
);
};
export default List;
고유한 ID(user.id)를 key로 사용하면 React가 효율적으로 업데이트 가능
2. index를 key로 사용하는 경우 (비권장)
const List = () => {
const items = ["🥕 당근", "🥒 오이", "🍆 가지"];
return (
<ul>
{items.map((item, index) => (
<li key={index}>{item}</li> // ⚠ index 사용 (데이터가 변하지 않는다면 괜찮음)
))}
</ul>
);
};
export default List;
🚨 경고: key={index}는 리스트가 동적으로 변경될 가능성이 없을 때만 사용해야 함.
(예: 정적 데이터, 변하지 않는 리스트)
데이터가 추가/삭제될 경우 index 기반의 key는 문제를 일으킬 수 있음.
(React가 항목을 잘못 매칭하여 UI 버그 발생 가능)
6. React 스타일링 방법 정리
React에서는 다양한 방식으로 스타일을 적용할 수 있습니다.
각 방법의 특징과 사용법을 살펴보겠습니다.
1️⃣ CSS-in-JS (styled-components, emotion)
JavaScript 코드 내에서 CSS를 작성하는 방식으로, 컴포넌트별로 스타일을 쉽게 관리할 수 있습니다.
styled-components 사용법
npm install styled-components
import styled from "styled-components";
const Button = styled.button`
background-color: #007bff;
color: white;
padding: 10px 20px;
border: none;
border-radius: 5px;
cursor: pointer;
&:hover {
background-color: #0056b3;
}
`;
const App = () => {
return <Button>클릭하세요</Button>;
};
export default App;
컴포넌트 기반 스타일링 (CSS가 자동으로 적용됨)
동적 스타일 적용 가능 (props 활용)
const Button = styled.button`
background-color: ${(props) => (props.primary ? "#007bff" : "#ccc")};
color: white;
`;
<Button primary>Primary 버튼</Button>
<Button>일반 버튼</Button>
2️⃣ CSS Modules
파일 단위로 고유한 클래스 이름을 자동 생성하여 충돌을 방지하는 방식.
설정 방법
파일명을 .module.css로 생성하면 자동으로 CSS Modules 방식이 적용됩니다.
/* Button.module.css */
.button {
background-color: #007bff;
color: white;
padding: 10px 20px;
border-radius: 5px;
}
import styles from "./Button.module.css";
const Button = () => {
return <button className={styles.button}>클릭하세요</button>;
};
export default Button;
CSS 클래스명이 자동으로 고유해져 충돌 방지됨.
기존 CSS 파일 방식을 유지하면서도 모듈화 가능.
3️⃣ Tailwind CSS
Utility-First CSS Framework로, 미리 정의된 클래스를 사용하여 빠르게 스타일을 적용하는 방식.
설치 방법
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init
tailwind.config.js에서 설정 후, index.css에 Tailwind 추가.
@tailwind base;
@tailwind components;
@tailwind utilities;
Tailwind 사용
const Button = () => {
return (
<button className="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-700">
클릭하세요
</button>
);
};
export default Button;
별도의 CSS 파일 없이 클래스만으로 스타일링 가능
반응형 디자인을 쉽게 적용 가능 (md:, lg: 같은 프리픽스 사용)
가독성이 떨어질 수 있음 (클래스명이 너무 길어질 수 있음)
4️⃣ Inline 스타일링 (style={{}})
style 속성에 객체 형태로 스타일을 직접 적용.
const Button = () => {
return (
<button
style={{
backgroundColor: "#007bff",
color: "white",
padding: "10px 20px",
borderRadius: "5px",
}}
>
클릭하세요
</button>
);
};
export default Button;
컴포넌트 내부에서 동적 스타일링 가능
CSS 파일 분리가 어렵고 가독성이 떨어짐
CSS 애니메이션 적용이 어려움 (일반적으로 className을 활용하는 것이 더 좋음)
'JavaScript > React' 카테고리의 다른 글
| useEffect, useLayoutEffect, useInsertionEffect (0) | 2025.03.21 |
|---|---|
| React Router DOM (0) | 2025.03.21 |
| React 프로그래밍을 위한 javascript 기본 (0) | 2025.03.21 |
| 서버 트래픽 비용을 줄이고 싶을 때, Squoosh (0) | 2025.03.06 |
| [React] function - export가 없는 경우, export가 있는 경우: export, export default의 차이 (0) | 2025.01.12 |