React 문서에 오신 것을 환영합니다! 이 페이지에서는 React 개념 중 일상적으로 사용하는 80%에 대한 소개를 제공합니다.
여러분은 다음을 배우게 됩니다.
- 컴포넌트를 만들고 중첩하는 방법
- 마크업과 스타일 추가 방법
- 데이터를 표시하는 방법
- 조건과 목록을 렌더링하는 방법
- 이벤트에 응답하고 화면을 업데이트하는 방법
- 컴포넌트 간 데이터 공유 방법
컴포넌트 만들기 및 중첩하기
React 앱은 컴포넌트로 구성됩니다. 컴포넌트는 자체 로직과 외형을 가진 UI(사용자 인터페이스)의 일부입니다. 컴포넌트는 버튼처럼 작을 수도 있고 페이지 전체처럼 크게 만들 수도 있습니다.
React 컴포넌트는 마크업을 반환하는 JavaScript 함수입니다.
function MyButton() {
return (
<button>I'm a button</button>
);
}
이제 MyButton을 다른 컴포넌트에 중첩시킬 수 있습니다.
export default function MyApp() {
return (
<div>
<h1>Welcome to my app</h1>
<MyButton />
</div>
);
}
<MyButton />가 대문자로 시작하는 것을 주목하세요. 이것이 React 컴포넌트임을 알 수 있는 방법입니다. React 컴포넌트 이름은 항상 대문자로 시작해야 하며 HTML 태그는 소문자여야 합니다.
결과를 살펴보겠습니다:
function MyButton() {
return (
<button>
I'm a button
</button>
);
}
export default function MyApp() {
return (
<div>
<h1>Welcome to my app</h1>
<MyButton />
</div>
);
}
export default 키워드는 파일 내의 주요 컴포넌트를 지정합니다. JavaScript 구문 중 일부를 이해하지 못하는 경우, MDN과 javascript.info에서 훌륭한 참고 자료를 찾을 수 있습니다.
JSX를 사용하여 마크업 작성하기
위에서 보여준 마크업 구문을 JSX라고 합니다. JSX는 선택 사항이지만, 대부분의 React 프로젝트에서는 편리함을 위해 JSX를 사용합니다. 로컬 개발을 위해 권장하는 모든 도구는 기본적으로 JSX를 지원합니다.
JSX는 HTML보다 엄격합니다. '<br />' 와 같이 태그를 닫아야 합니다. 컴포넌트는 여러 개의 JSX 태그를 반환할 수 없습니다. 공통 부모인 '<div>...</div>' 또는 빈 '<>...</>' 래퍼로 감싸야 합니다.
function AboutPage() {
return (
<>
<h1>About</h1>
<p>Hello there.<br />How do you do?</p>
</>
);
}
많은 양의 HTML을 JSX로 변환해야 하는 경우 온라인 변환 도구를 사용할 수 있습니다.
스타일 추가
React에서는 CSS 클래스를 'className' 으로 지정합니다. HTML 클래스 속성과 동일하게 작동합니다.
<img className="avatar" />
그런 다음 별도의 CSS 파일에서 해당 클래스에 대한 CSS 규칙을 작성합니다.
/* In your CSS */
.avatar {
border-radius: 50%;
}
React는 CSS 파일을 추가하는 방법을 정하지 않습니다. 가장 간단한 경우에는 HTML에 <link> 태그를 추가할 수 있습니다. 빌드 도구나 프레임워크를 사용하는 경우 해당 문서를 참조하여 프로젝트에 CSS 파일을 추가하는 방법을 알아보세요.
데이터 표시
JSX를 사용하면 JavaScript 내에 마크업을 넣을 수 있습니다. 중괄호 '{}' 를 사용하여 코드에서 변수를 임베드하고 사용자에게 표시할 수 있습니다.
return (
<h1>
{user.name}
</h1>
);
JSX 속성에서도 JSX 속성에서도 JavaScript로 "탈출"할 수 있지만 따옴표 대신 중괄호를 사용해야 합니다. 예를 들어, className="avatar"는 "avatar" 문자열을 CSS 클래스로 전달하지만 src={user.imageUrl}는 JavaScript user.imageUrl 변수 값을 읽고 그 값을 src 속성으로 전달합니다:
return (
<img
className="avatar"
src={user.imageUrl}
/>
);
JSX 중괄호 안에는 더 복잡한 표현식도 넣을 수 있습니다. 예를 들어 문자열 연결을 할 수 있습니다:
const user = {
name: 'Hedy Lamarr',
imageUrl: 'https://i.imgur.com/yXOvdOSs.jpg',
imageSize: 90,
};
export default function Profile() {
return (
<>
<h1>{user.name}</h1>
<img
className="avatar"
src={user.imageUrl}
alt={'Photo of ' + user.name}
style={{
width: user.imageSize,
height: user.imageSize
}}
/>
</>
);
}
위의 예제에서 style={{}}는 특별한 문법이 아닌, JSX 중괄호 내에서의 일반 {} 객체입니다. 스타일이 JavaScript 변수에 의존하는 경우 style 속성을 사용할 수 있습니다.
조건부 렌더링
React에서 조건을 작성하는 특별한 구문은 없습니다. 일반 JavaScript 코드를 작성할 때와 같은 기술을 사용합니다.
예를 들어, 조건부로 JSX를 포함하려면 if 문을 사용할 수 있습니다:
let content;
if (isLoggedIn) {
content = <AdminPanel />;
} else {
content = <LoginForm />;
}
return (
<div>
{content}
</div>
);
조건부 코드를 더 간결하게 작성하려면 삼항 연산자 '?' 를 사용할 수 있습니다.
이 연산자는 JSX 내부에서도 사용할 수 있습니다.
<div>
{isLoggedIn ? (
<AdminPanel />
) : (
<LoginForm />
)}
</div>
만약 else 분기가 필요하지 않다면, 더 짧은 논리 연산자 && 문법을 사용할 수도 있습니다:
<div>
{isLoggedIn && <AdminPanel />}
</div>
모든 이러한 방법은 속성을 조건적으로 지정하는 데도 적용됩니다. JavaScript 구문에 익숙하지 않다면 항상 if...else를 사용하여 시작할 수 있습니다.
목록 렌더링
목록을 렌더링하기 위해 for 루프와 배열의 'map()' 함수와 같은 JavaScript 기능을 사용합니다.
const products = [
{ title: 'Cabbage', id: 1 },
{ title: 'Garlic', id: 2 },
{ title: 'Apple', id: 3 },
];
컴포넌트 내부에서 map() 함수를 사용하여 제품 배열을 <li> 항목 배열로 변환할 수 있습니다.
const listItems = products.map(product =>
<li key={product.id}>
{product.title}
</li>
);
return (
<ul>{listItems}</ul>
);
<li>에 key 속성이 있는 것을 주목하세요. 목록의 각 항목마다 해당 항목을 형제 항목 중에서 고유하게 식별하는 문자열 또는 숫자를 전달해야 합니다. 일반적으로 키는 데이터에서 가져와야 하며, 예를 들어 데이터베이스 ID와 같습니다. React는 향후 항목을 삽입, 삭제 또는 재정렬하는 경우에 대비하여 키를 사용하여 무엇이 발생했는지를 파악합니다.
const products = [
{ title: 'Cabbage', isFruit: false, id: 1 },
{ title: 'Garlic', isFruit: false, id: 2 },
{ title: 'Apple', isFruit: true, id: 3 },
];
export default function ShoppingList() {
const listItems = products.map(product =>
<li
key={product.id}
style={{
color: product.isFruit ? 'magenta' : 'darkgreen'
}}
>
{product.title}
</li>
);
return (
<ul>{listItems}</ul>
);
}
이벤트에 응답하기
컴포넌트 내에서 이벤트 함수를 선언하여 이벤트에 응답할 수 있습니다.
function MyButton() {
function handleClick() {
alert('You clicked me!');
}
return (
<button onClick={handleClick}>
Click me
</button>
);
}
주목하세요, onClick={handleClick}에서는 괄호가 끝에 없습니다! 이벤트 핸들러 함수를 호출하지 마세요. 단순히 이벤트 핸들러 함수를 전달하면 됩니다. 사용자가 버튼을 클릭할 때 React가 이벤트 핸들러를 호출합니다.
화면 업데이트
컴포넌트가 정보를 기억하고 표시하도록 하려면 컴포넌트에 상태(state)를 추가하면 됩니다. 상태를 추가하려면 React에서 useState를 가져와야 합니다.
import { useState } from 'react';
이제 컴포넌트 내에서 상태 변수를 선언할 수 있습니다.
function MyButton() {
const [count, setCount] = useState(0);
// ...
useState를 사용하면 두 가지를 얻을 수 있습니다. 현재 상태(count)와 상태를 업데이트하는 함수(setCount)입니다. 이들에게는 어떤 이름을 지정해도 되지만, 보통 [something, setSomething] 형식으로 작성하는 관례가 있습니다.
버튼이 처음 표시될 때 count는 0입니다. 왜냐하면 useState()에 0을 전달했기 때문입니다. 상태를 변경하려면 setCount()를 호출하고 새 값을 전달하면 됩니다. 이 버튼을 클릭하면 카운터가 증가합니다:
function MyButton() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
}
return (
<button onClick={handleClick}>
Clicked {count} times
</button>
);
}
React는 컴포넌트 함수를 다시 호출할 것입니다. 이번에는 count가 1이 될 것입니다. 그리고 2가 될 것입니다. 이런 식으로 계속됩니다.
같은 컴포넌트를 여러 번 렌더링하는 경우 각각이 고유한 상태를 가져옵니다. 각 버튼을 별도로 클릭하세요:
import { useState } from 'react';
export default function MyApp() {
return (
<div>
<h1>Counters that update separately</h1>
<MyButton />
<MyButton />
</div>
);
}
function MyButton() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
}
return (
<button onClick={handleClick}>
Clicked {count} times
</button>
);
}
각 버튼이 자체적인 count 상태를 "기억"하고 다른 버튼에 영향을 미치지 않는 것을 주목하세요.
Hooks 사용
Hooks는 use로 시작하는 함수들을 가리킵니다. useState는 React에서 제공하는 내장 Hook 중 하나입니다. 다른 내장 Hook은 API 레퍼런스에서 찾을 수 있습니다. 또한 기존 Hook을 결합하여 사용자 정의 Hook을 작성할 수도 있습니다.
Hooks는 다른 함수들보다 제약이 있습니다. Hooks는 컴포넌트의 맨 위에서만 호출할 수 있습니다(또는 다른 Hook 내에서). 만약 조건문이나 반복문에서 useState를 사용하려면 새로운 컴포넌트를 추출하고 거기에 넣어야 합니다.
컴포넌트 간 데이터 공유
각각의 MyButton이 독립적인 count를 가지고 있고, 각 버튼이 클릭이 될 때마다 해당 버튼의 count만 변경한다는 것을 보았습니다.
그러나 종종 컴포넌트가 데이터를 공유하고 항상 함께 업데이트 해야 할 때가 있습니다.
MyButton 컴포넌트가 동일한 카운트를 표시하고 함께 업데이트하려면 개별 버튼에서 상태를 가장 가까운 모든 버튼을 포함하는 컴포넌트로 "위로" 이동해야 합니다.
이 예제에서는 MyApp입니다:
이제 버튼 중 하나를 클릭하면 MyApp의 카운트가 변경되어 MyButton의 카운트도 모두 변경됩니다. 이를 코드로 어떻게 표현할 수 있는지 살펴보겠습니다.
먼저 MyButton에서 상태를 MyApp으로 옮겨보세요:
export default function MyApp() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
}
return (
<div>
<h1>Counters that update together</h1>
<MyButton count={count} onClick={handleClick} />
<MyButton count={count} onClick={handleClick} />
</div>
);
}
function MyButton() {
// ... we're moving code from here ...
}
그런 다음, 상태를 MyApp에서 각 MyButton으로 내려보세요. 공유된 클릭 핸들러와 함께 정보를 MyButton에 전달할 수 있습니다. <img>와 같은 내장 태그를 사용했던 것과 마찬가지로 JSX 중괄호를 사용하여 MyButton에 정보를 전달할 수 있습니다:
export default function MyApp() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
}
return (
<div>
<h1>Counters that update together</h1>
<MyButton count={count} onClick={handleClick} />
<MyButton count={count} onClick={handleClick} />
</div>
);
}
이렇게 전달하는 정보를 프롭스(props)라고 합니다. 이제 MyApp 컴포넌트에는 count 상태와 handleClick 이벤트 핸들러가 포함되어 있으며, 두 항목을 각 버튼에 프롭(props)으로 전달합니다.
마지막으로, MyButton을 변경하여 부모 컴포넌트에서 전달한 프롭(props)을 읽도록 하세요:
function MyButton({ count, onClick }) {
return (
<button onClick={onClick}>
Clicked {count} times
</button>
);
}
버튼을 클릭하면 onClick 핸들러가 실행됩니다. 각 버튼의 onClick 프롭(props)은 MyApp 내부의 handleClick 함수로 설정되었으므로 해당 함수 내의 코드가 실행됩니다. 이 코드는 setCount(count + 1)을 호출하여 count 상태 변수를 증가시킵니다. 그런 다음 새로운 count 값이 각 버튼에 프롭(props)으로 전달되어 모든 버튼에서 새로운 값을 표시합니다. 이것을 "상태 끌어올리기(lifting state up)"라고 합니다. 상태를 끌어올려서 컴포넌트 간에 공유하게 되었습니다.
import { useState } from 'react';
export default function MyApp() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
}
return (
<div>
<h1>Counters that update together</h1>
<MyButton count={count} onClick={handleClick} />
<MyButton count={count} onClick={handleClick} />
</div>
);
}
function MyButton({ count, onClick }) {
return (
<button onClick={onClick}>
Clicked {count} times
</button>
);
}
다음 단계
지금까지 React 코드를 작성하는 기본 사항을 배웠습니다!
Tutorial을 확인하여 배운 내용을 실제로 적용하고 React로 첫 번째 미니 앱을 만들어보세요.
'Dev > React' 카테고리의 다른 글
React 상태 관리: 깊이 있게 파헤치기 (0) | 2024.11.10 |
---|---|
React 19 RC 버전: 더욱 강력해진 React 개발 경험 (4) | 2024.11.09 |
[공식문서] React 배우기 - UI 구성하기 (0) | 2023.09.22 |
[공식문서] React - React로 사고하기 (0) | 2023.09.17 |
[공식문서] React - 튜토리얼: Tic-Tac-Toe (0) | 2023.09.16 |