React 컴포넌트란?
-> 함수 컴포넌트 만들기와 부모·자식 컴포넌트 구조
이번에는 React의 가장 기본적인 개념인 컴포넌트(Component)에 대해 알아보겠습니다.
React는 화면을 하나의 거대한 코드로 만드는 것이 아니라, 화면을 여러 개의 작은 단위로 나누어 개발합니다.
이때 화면을 구성하는 각각의 단위를 컴포넌트라고 합니다.
1. React 컴포넌트란?
이전에 작성한 App.jsx 파일을 보면 다음과 같은 코드가 있습니다.
function App() {
return (
<>
<h1>안녕 리액트.</h1>
</>
)
}
export default App
일반적인 JavaScript 함수와 비슷하지만, React에서는 JSX를 반환하는 함수를 만들 수 있습니다.
이러한 함수를 React에서는 컴포넌트(Component)라고 부릅니다.
위 코드의 경우 함수 이름이 App이므로 App 컴포넌트라고 부릅니다.
즉, 다음과 같이 이해할 수 있습니다.
JSX를 반환하는 JavaScript 함수 → React 컴포넌트
그리고 함수로 작성한 컴포넌트를 함수 컴포넌트(Function Component)라고 부릅니다.
2. Header 컴포넌트 만들기
App 컴포넌트와 마찬가지로 Header 컴포넌트도 만들 수 있습니다.
function Header() {
return (
<header>
<h1>header</h1>
</header>
)
}
이렇게 작성하면 Header라는 React 컴포넌트가 만들어집니다.
컴포넌트는 일반 함수처럼 이름을 이용해 호출하는 것이 아니라 JSX 문법을 사용하여 화면에 배치합니다.
<Header />
3. 화살표 함수로 컴포넌트 만들기
React 컴포넌트는 일반적인 함수 선언식뿐만 아니라 화살표 함수로도 만들 수 있습니다.
const Header = () => {
return (
<header>
<h1>header</h1>
</header>
)
}
React에서는 두 방식 모두 많이 사용됩니다.
함수 선언식
function Header() {
return (
<header>
<h1>header</h1>
</header>
)
}
화살표 함수
const Header = () => {
return (
<header>
<h1>header</h1>
</header>
)
}
프로젝트에서 사용하는 코드 스타일에 맞춰 일관되게 작성하면 됩니다.
4. React 컴포넌트 이름은 반드시 대문자로 시작해야 한다
React 컴포넌트를 만들 때 중요한 규칙이 하나 있습니다.
컴포넌트의 이름은 반드시 대문자로 시작해야 합니다.
예를 들어 다음은 올바른 컴포넌트 이름입니다.
const Header = () => {
return <h1>header</h1>
}
하지만 다음과 같이 소문자로 시작하면 React는 일반 HTML 태그로 인식할 수 있습니다.
const header = () => {
return <h1>header</h1>
}
따라서 React 컴포넌트를 만들 때는 다음과 같이 작성합니다.
App
Header
Footer
Main
Profile
UserInfo
컴포넌트 이름의 첫 글자는 항상 대문자로 작성하는 것이 중요합니다.
5. 클래스 컴포넌트와 함수 컴포넌트
React에서는 과거부터 클래스를 이용해 컴포넌트를 만들 수도 있습니다.
하지만 클래스 컴포넌트는 작성해야 하는 코드가 많고 구조가 복잡해질 수 있습니다.
현재 React에서는 일반적으로 함수 컴포넌트와 Hooks를 사용하는 방식이 주로 사용됩니다.
따라서 앞으로는 다음과 같은 함수 형태의 컴포넌트를 중심으로 작성하면 됩니다.
const Header = () => {
return (
<header>
<h1>header</h1>
</header>
)
}
6. 컴포넌트를 만들기만 해서는 화면에 표시되지 않는다
App.jsx에 Header 컴포넌트를 추가했다고 해서 자동으로 화면에 표시되는 것은 아닙니다.
예를 들어 다음과 같이 Header 컴포넌트를 작성했다고 가정해 보겠습니다.
function Header() {
return (
<header>
<h1>header</h1>
</header>
)
}
그런데 브라우저에는 header가 표시되지 않을 수 있습니다.
그 이유는 React가 처음 렌더링하는 컴포넌트를 main.jsx에서 확인할 수 있기 때문입니다.
createRoot(document.getElementById('root')).render(
<App />
)
여기서 React는 <App /> 컴포넌트를 화면에 렌더링하고 있습니다.
즉, 현재 화면에 표시되는 시작점은 App 컴포넌트입니다.
Header 컴포넌트를 화면에 표시하려면 App 컴포넌트 안에서 사용해야 합니다.
7. 컴포넌트 안에서 다른 컴포넌트 사용하기
App 컴포넌트 안에 Header를 추가해 보겠습니다.
function App() {
return (
<>
<Header />
<h1>안녕 리액트.</h1>
</>
)
}
이제 React는 다음과 같은 구조로 컴포넌트를 렌더링합니다.
App
├─ Header
└─ h1
App이 렌더링되면서 내부에 작성된 Header 컴포넌트도 함께 렌더링됩니다.
8. 부모 컴포넌트와 자식 컴포넌트
위와 같은 구조에서 App과 Header는 부모와 자식 관계를 가집니다.
App
└─ Header
이때,
- App → 부모 컴포넌트
- Header → 자식 컴포넌트
라고 부릅니다.
컴포넌트는 다른 컴포넌트 내부에서 사용할 수 있기 때문에 이러한 트리 구조를 만들 수 있습니다.
예를 들어 App 컴포넌트가 여러 컴포넌트를 포함하고 있다면 다음과 같은 구조가 됩니다.
App
├─ Header
├─ Main
└─ Footer
이 경우 App은 최상위에서 여러 컴포넌트를 관리하는 Root 컴포넌트 역할을 할 수 있습니다.
또한 모든 하위 컴포넌트의 상위에 있기 때문에 문맥에 따라 조상 컴포넌트라고 표현하기도 합니다.
일반적인 React 프로젝트에서는 App 컴포넌트를 애플리케이션의 주요 루트 컴포넌트로 사용하는 경우가 많습니다.
9. 컴포넌트는 파일별로 분리해서 관리하기
컴포넌트가 많아지면 하나의 파일에 모든 컴포넌트를 작성하는 것은 관리하기 어려워집니다.
따라서 일반적으로는 컴포넌트별로 파일을 분리하여 관리합니다.
예를 들어 다음과 같은 구조로 구성할 수 있습니다.
src
├─ components
│ ├─ Header.jsx
│ ├─ Main.jsx
│ └─ Footer.jsx
├─ App.jsx
├─ App.css
├─ index.css
└─ main.jsx
이렇게 구성하면 각 컴포넌트의 역할을 쉽게 구분하고 관리할 수 있습니다.
10. Header 컴포넌트 만들기
먼저 components/Header.jsx 파일을 생성합니다.
const Header = () => {
return (
<header>
<h1>header</h1>
</header>
)
}
export default Header
마지막에 다음 코드를 작성합니다.
export default Header
이 코드는 Header 컴포넌트를 다른 파일에서 사용할 수 있도록 내보내는 역할을 합니다.
11. Main 컴포넌트 만들기
components/Main.jsx 파일을 생성합니다.
const Main = () => {
return (
<main>
<h1>main</h1>
</main>
)
}
export default Main
12. Footer 컴포넌트 만들기
components/Footer.jsx 파일을 생성합니다.
const Footer = () => {
return (
<footer>
<h1>footer</h1>
</footer>
)
}
export default Footer
이제 Header, Main, Footer 컴포넌트를 각각 파일로 분리했습니다.
13. App.jsx에서 컴포넌트 불러오기
분리한 컴포넌트를 사용하려면 App.jsx에서 import 해야 합니다.
import Header from './components/Header'
import Main from './components/Main'
import Footer from './components/Footer'
그다음 JSX에서 컴포넌트를 사용합니다.
import Header from './components/Header'
import Main from './components/Main'
import Footer from './components/Footer'
function App() {
return (
<>
<Header />
<Main />
<Footer />
</>
)
}
export default App
이제 화면에는 세 개의 컴포넌트가 순서대로 렌더링됩니다.
header
main
footer
14. import에서 .jsx 확장자 생략하기
컴포넌트를 import할 때 다음과 같이 확장자까지 작성할 수도 있습니다.
import Header from './components/Header.jsx'
하지만 일반적으로 .jsx 확장자는 생략할 수 있습니다.
import Header from './components/Header'
Vite를 이용한 React 프로젝트에서는 이러한 모듈 파일을 해석할 수 있도록 기본 설정이 되어 있기 때문입니다.
따라서 보통 다음과 같이 확장자를 생략해서 작성합니다.
import Header from './components/Header'
import Main from './components/Main'
import Footer from './components/Footer'
15. 최종 컴포넌트 구조
현재 만든 컴포넌트 구조를 그림으로 표현하면 다음과 같습니다.
App
│
┌─────────┼─────────┐
│ │ │
Header Main Footer
React는 이렇게 컴포넌트를 트리 형태로 구성합니다.
가장 상위에 있는 App 컴포넌트가 렌더링되고, App 내부에서 사용한 Header, Main, Footer 컴포넌트가 차례대로 렌더링됩니다.
프로젝트 규모가 커질수록 이러한 컴포넌트 구조는 더욱 복잡해질 수 있습니다.
App
├─ Header
│ ├─ Logo
│ └─ Navigation
├─ Main
│ ├─ Content
│ └─ Sidebar
└─ Footer
따라서 React에서는 화면을 적절한 단위로 나누고 각각을 컴포넌트로 만들어 관리하는 것이 중요합니다.
마무리
이번에는 React의 핵심 개념인 컴포넌트에 대해 알아보았습니다.
정리하면 다음과 같습니다.
- React에서는 JSX를 반환하는 함수를 컴포넌트로 만들 수 있다.
- 함수로 만든 컴포넌트를 함수 컴포넌트라고 한다.
- 컴포넌트 이름은 반드시 대문자로 시작해야 한다.
- 컴포넌트는 일반 함수 선언식 또는 화살표 함수로 만들 수 있다.
- 컴포넌트를 만들기만 해서는 화면에 표시되지 않으며, 렌더링되는 컴포넌트 내부에서 사용해야 한다.
- 다른 컴포넌트 내부에서 사용되는 컴포넌트는 자식 컴포넌트가 된다.
- 자식 컴포넌트를 포함하는 컴포넌트는 부모 컴포넌트가 된다.
- 일반적으로 컴포넌트는 역할별로 파일을 분리하여 관리한다.
- export를 통해 컴포넌트를 내보내고, 다른 파일에서 import하여 사용할 수 있다.
- 여러 컴포넌트를 조합하여 하나의 화면을 구성할 수 있다.
React 개발은 결국 작은 컴포넌트를 만들고, 이를 조합하여 화면을 구성하는 방식이라고 볼 수 있습니다.
다음부터는 이렇게 만든 컴포넌트에 데이터를 전달하거나 상태를 관리하는 방법을 학습하면 React의 동작 방식을 더욱 잘 이해할 수 있습니다.