React에서 컴포넌트와 JSX는 애플리케이션의 구조와 UI를 설계하고 구성하는 핵심 개념입니다.
1. 컴포넌트(Component)란?
컴포넌트는 React 애플리케이션의 UI를 구성하는 독립적이고 재사용 가능한 단위입니다. 컴포넌트는 React 애플리케이션을 작고 관리하기 쉬운 여러 조각으로 나누어, 각 조각이 자체적으로 동작하도록 합니다. 각 컴포넌트는 HTML, CSS, JavaScript를 포함하여 하나의 UI 요소를 나타내며, 다른 컴포넌트와 결합해 더 복잡한 UI를 구성할 수 있습니다.
컴포넌트의 종류
React 컴포넌트는 두 가지 종류로 나뉩니다:
- 함수형 컴포넌트: JavaScript 함수를 사용하여 정의합니다. React Hooks와 함께 사용하여 상태와 라이프사이클 관련 기능을 처리할 수 있습니다.
- 클래스형 컴포넌트: ES6 클래스 문법을 사용하여 정의하며, state와 lifecycle 메서드를 포함할 수 있습니다. 그러나 React 16.8 버전 이후로 함수형 컴포넌트와 Hooks가 많이 사용되고 있습니다.
함수형 컴포넌트 예제:
// Greeting.js
const Greeting = () => <h1>Hello, World!</h1>;
export default Greeting;
// App.js
import React from 'react';
import Greeting from './Greeting'; // Greeting 컴포넌트 import
function App() {
return (
<div>
<Greeting /> {/* Greeting 컴포넌트를 렌더링 */}
</div>
);
}
export default App;
import React from 'react';는 React 라이브러리를 가져와서 React의 기능을 사용할 수 있게 하는 코드입니다. 이 문장이 필요한 이유는 React가 JSX(자바스크립트 확장 문법)를 이해하고 변환하기 위해 라이브러리를 참조하기 때문입니다.
import React from 'react'; 의 의미
- JSX 변환: import React는 JSX 코드가 JavaScript로 변환될 때 React 라이브러리를 사용할 수 있게 합니다. JSX는 XML과 유사한 문법으로 HTML 태그처럼 컴포넌트를 작성할 수 있지만, 실제로는 React.createElement 함수를 호출하는 JavaScript 코드로 변환됩니다.
- React 기능 사용: React에서 제공하는 훅(hook)이나 Component 클래스 같은 기능들을 사용하려면 React를 import해야 합니다.
최신 버전의 React에서의 변화
React 17 이후 버전에서는 JSX를 사용할 때 React를 명시적으로 import할 필요가 없어졌습니다. 이는 컴파일러가 자동으로 React.createElement를 참조하도록 설정되었기 때문입니다. 따라서 최신 React 프로젝트에서는 import React from 'react'; 구문 없이도 JSX 문법을 사용할 수 있습니다.
예를 들어, 최신 React에서는 import React from 'react'; 없이 아래와 같이 작성해도 정상적으로 작동합니다:
// App.js
import Greeting from './Greeting';
function App() {
return (
<div>
<Greeting />
</div>
);
}
export default App;
이렇게 import React from 'react';를 생략할 수 있는 이유는 최신 빌드 도구와 컴파일러가 JSX를 자동으로 변환해 주기 때문입니다.
클래스형 컴포넌트 예제:
import React, { Component } from 'react';
class Greeting extends Component {
constructor(props) {
super(props);
this.state = {
name: 'World',
isGreetingVisible: true,
clickCount: 0,
};
}
toggleGreeting = () => {
this.setState((prevState) => ({
isGreetingVisible: !prevState.isGreetingVisible,
}));
};
handleNameChange = (event) => {
this.setState({ name: event.target.value });
};
incrementClickCount = () => {
this.setState((prevState) => ({
clickCount: prevState.clickCount + 1,
}));
};
render() {
const { name, isGreetingVisible, clickCount } = this.state;
return (
<div>
<h1>{isGreetingVisible ? `Hello, ${name}!` : 'Greeting Hidden'}</h1>
<button onClick={this.toggleGreeting}>
{isGreetingVisible ? 'Hide Greeting' : 'Show Greeting'}
</button>
<input
type="text"
value={name}
onChange={this.handleNameChange}
placeholder="Enter your name"
/>
<p>
You've clicked <strong>{clickCount}</strong> times.
</p>
<button onClick={this.incrementClickCount}>Click Me</button>
</div>
);
}
}
export default Greeting;
코드 설명
- 상태(state) 관리:
- name: 인사할 이름을 관리합니다.
- isGreetingVisible: 인사말을 표시할지 숨길지를 결정하는 상태입니다.
- clickCount: 버튼을 클릭한 횟수를 관리합니다.
- 메서드:
- toggleGreeting: 인사말의 표시 여부를 토글합니다.
- handleNameChange: 입력된 이름을 name 상태로 업데이트합니다.
- incrementClickCount: 클릭 횟수를 증가시킵니다.
- 조건부 렌더링:
- isGreetingVisible에 따라 인사말을 표시하거나 숨깁니다.
- 이벤트 핸들링:
- 버튼 클릭 시 인사말 표시 여부를 전환하고, 클릭 횟수를 증가시키며, 입력 필드에서 이름을 실시간으로 업데이트합니다.
이 예제는 다양한 상태와 메서드가 포함되어 있어 클래스형 컴포넌트의 기능을 충분히 보여줍니다.
2. JSX란?
JSX는 JavaScript XML의 약자로, JavaScript 안에서 HTML을 작성할 수 있도록 하는 문법입니다. JSX를 사용하면 코드가 읽기 쉬워지고, UI의 구조를 직관적으로 표현할 수 있습니다. React에서는 JSX를 사용해 컴포넌트의 UI를 정의하는 것이 일반적입니다.
JSX의 특징
- HTML과 유사한 문법: JSX는 HTML과 매우 유사한 문법을 사용하므로, 웹 개발 경험이 있다면 쉽게 작성할 수 있습니다.
- JavaScript 표현식 사용: {}를 사용하여 JavaScript 표현식을 삽입할 수 있습니다.
- JSX는 결국 JavaScript: JSX는 Babel과 같은 컴파일러에 의해 JavaScript로 변환되어 실행됩니다. 실제로는 React.createElement()로 변환되어 DOM을 조작합니다.
JSX 예시
아래는 JSX에서 다양한 JavaScript 표현식, 조건부 렌더링, 리스트 렌더링 등을 사용하는 예제입니다.
import React from 'react';
function App() {
const user = {
firstName: 'John',
lastName: 'Doe',
hobbies: ['Reading', 'Traveling', 'Cooking', 'Swimming'],
isLoggedIn: true,
friends: [
{ id: 1, name: 'Alice', age: 25 },
{ id: 2, name: 'Bob', age: 30 },
{ id: 3, name: 'Charlie', age: 35 },
],
};
function renderGreeting(user) {
if (user.isLoggedIn) {
return <h1>Welcome back, {user.firstName} {user.lastName}!</h1>;
} else {
return <h1>Welcome, Guest!</h1>;
}
}
return (
<div>
{renderGreeting(user)}
<h2>Your Hobbies:</h2>
<ul>
{user.hobbies.map((hobby, index) => (
<li key={index}>{hobby}</li>
))}
</ul>
<h2>Your Friends:</h2>
<ul>
{user.friends.map((friend) => (
<li key={friend.id}>
<strong>{friend.name}</strong> - Age: {friend.age}
{friend.age > 30 ? ' (Senior Friend)' : ' (Junior Friend)'}
</li>
))}
</ul>
<p>
You have <strong>{user.friends.length}</strong> friends and{' '}
<strong>{user.hobbies.length}</strong> hobbies.
</p>
<h3>{`Hello, ${user.firstName}! Today is ${new Date().toLocaleDateString()}.`}</h3>
</div>
);
}
export default App;
코드 설명
- 조건부 렌더링:
- isLoggedIn 상태를 사용하여 사용자 로그인 여부에 따라 다른 인사말을 표시합니다.
- 배열의 map() 메서드로 리스트 렌더링:
- user.hobbies 배열을 순회하여 취미 목록을 <ul>로 렌더링합니다.
- user.friends 배열도 순회하여 친구 목록을 렌더링하며, 친구 나이에 따라 ‘(Senior Friend)’ 또는 ‘(Junior Friend)’를 조건부로 표시합니다.
- JSX에서 JavaScript 표현식 사용:
- 문자열 보간({})을 사용해 변수나 연산 결과를 텍스트로 렌더링합니다.
- 현재 날짜를 new Date().toLocaleDateString()으로 표시합니다.
- 자바스크립트 함수 호출:
- renderGreeting(user) 함수를 호출하여 JSX에서 인사말을 동적으로 렌더링합니다.
이 예제는 다양한 기능을 활용하여 JSX에서 더 복잡한 표현식과 렌더링 방식을 보여줍니다.
컴포넌트와 JSX의 관계
React에서 컴포넌트는 JSX를 사용하여 UI를 정의하며, JSX를 통해 컴포넌트의 상태나 속성(props)을 기반으로 동적으로 UI를 렌더링할 수 있습니다. 컴포넌트를 통해 작은 단위로 쪼개진 UI 요소들을 조합하여 복잡한 애플리케이션을 구축하는 방식이 React의 핵심입니다.
결론
- 컴포넌트는 UI의 재사용 가능한 조각이며, JSX는 컴포넌트 안에서 UI를 작성하는 문법입니다.
- 컴포넌트와 JSX를 함께 사용하면 코드가 더 직관적이고 구조적으로 관리가 쉬운 React 애플리케이션을 만들 수 있습니다.
ES6
ES6(ECMAScript 2015)는 자바스크립트의 중요한 업데이트로, 2015년에 발표된 ECMAScript 사양입니다. ES6는 자바스크립트 언어에 새로운 문법과 기능을 도입하여 개발자들이 코드를 더 간결하고 효율적으로 작성할 수 있도록 합니다. ES6에서 추가된 주요 기능은 변수 선언, 함수 기능 개선, 객체와 배열 관리, 클래스 도입 등입니다.
ES6의 주요 기능
- let과 const 키워드:
- let: 블록 범위 스코프를 가지며, 중복 선언을 허용하지 않습니다.
- const: 한 번 할당되면 값이 변경되지 않는 상수를 선언합니다. const로 선언된 객체나 배열의 속성 값은 변경 가능하나, 참조 자체는 변경할 수 없습니다.
let age = 30; const name = "Alice";
- 화살표 함수 (Arrow Functions):
- 화살표 함수는 간결한 문법으로 함수를 작성할 수 있으며, this의 스코프를 유지합니다.
const add = (a, b) => a + b; console.log(add(3, 4)); // 7
- 템플릿 리터럴 (Template Literals):
- 백틱(`)을 사용해 문자열 안에서 표현식을 쉽게 삽입할 수 있으며, 여러 줄 문자열 작성도 가능합니다.
const name = "Alice"; const message = `Hello, ${name}!`; console.log(message); // "Hello, Alice!"
- 디스트럭처링 (Destructuring):
- 객체나 배열에서 필요한 값만을 쉽게 추출할 수 있도록 해줍니다.
const person = { name: "Alice", age: 30 }; const { name, age } = person; const numbers = [1, 2, 3]; const [first, second] = numbers;
- Default Parameters:
- 함수 파라미터에 디폴트 값을 지정하여, 호출 시 값이 없으면 디폴트 값을 사용하게 합니다.
function greet(name = "Guest") { return `Hello, ${name}`; }
- 전개 연산자 (Spread Operator) 및 Rest 파라미터 (Rest Parameters):
- ... 문법을 사용하여 배열이나 객체의 값을 쉽게 복사하거나 결합할 수 있습니다. 함수의 Rest 파라미터로도 사용 가능합니다.
const arr1 = [1, 2]; const arr2 = [...arr1, 3, 4]; // [1, 2, 3, 4] function sum(...numbers) { return numbers.reduce((total, num) => total + num, 0); }
- 클래스 (Classes):
- 자바스크립트에 객체 지향 프로그래밍 패턴을 쉽게 구현할 수 있도록 클래스를 도입했습니다. ES5의 프로토타입 기반 객체 생성 방식을 대체하는 기능입니다.
class Person { constructor(name, age) { this.name = name; this.age = age; } greet() { return `Hello, my name is ${this.name}`; } }
- 모듈 (Modules):
- import와 export 키워드를 사용하여 모듈화가 가능해졌습니다. 이를 통해 코드를 여러 파일로 나누고 재사용성을 높일 수 있습니다.
// person.js export const name = "Alice"; // main.js import { name } from './person.js';
- Promise:
- 비동기 작업을 쉽게 처리할 수 있도록 도입된 객체입니다. then, catch 메서드를 통해 비동기 작업의 성공과 실패를 다룰 수 있습니다.
const fetchData = () => new Promise((resolve, reject) => { setTimeout(() => resolve("Data received"), 1000); }); fetchData().then(data => console.log(data)).catch(error => console.error(error));
요약
ES6는 자바스크립트에 많은 새로운 기능과 문법을 도입하여 개발자들이 효율적으로 코드를 작성할 수 있도록 돕습니다. 특히, 코드의 가독성과 유지보수성을 높이고, 모듈화 및 객체 지향 프로그래밍을 쉽게 구현할 수 있도록 하는 다양한 기능들이 추가되었습니다.