컨텐츠로 건너뛰기

컴포넌트

Astro 컴포넌트는 모든 Astro 프로젝트의 기본 구성 요소입니다. 클라이언트 측 런타임이 없는 HTML 전용 템플릿 컴포넌트이며 .astro 파일 확장자를 사용합니다.

Astro 컴포넌트는 매우 유연합니다. Astro 컴포넌트는 SEO 작업을 쉽게 만들어주는 공통 <meta> 태그 모음과 같은 작은 HTML 스니펫만큼 작을 수 있습니다. 컴포넌트는 헤더나 프로필 카드와 같은 재사용 가능한 UI 요소가 될 수 있습니다. Astro 컴포넌트는 전체 페이지 레이아웃을 포함할 수도 있으며, 특수한 src/pages/ 폴더에 위치할 경우 전체 페이지 자체가 될 수도 있습니다.

Astro 컴포넌트의 가장 중요한 점은 클라이언트에서 렌더링되지 않는다는 것입니다. 빌드 타임 또는 요청 시 HTML로 렌더링됩니다. 컴포넌트 프런트매터에 JavaScript 코드를 포함할 수 있으며, 이 모든 코드는 사용자 브라우저로 전송되는 최종 페이지에서 제거됩니다. 그 결과, 기본적으로 추가되는 JavaScript 부하가 전혀 없는 더 빠른 사이트가 됩니다.

Astro 컴포넌트에 클라이언트 측 상호 작용이 필요한 경우, 표준 HTML <script> 태그 또는 UI 프레임워크 컴포넌트를 “클라이언트 아일랜드”로 추가할 수 있습니다.

개인화되거나 동적인 콘텐츠를 렌더링해야 하는 컴포넌트의 경우, 서버 지시어를 추가하여 서버 렌더링을 연기할 수 있습니다. 이러한 “서버 아일랜드”는 전체 페이지 로드를 지연시키지 않고 사용 가능한 시점에 콘텐츠를 렌더링합니다.

Astro 컴포넌트는 두 가지 주요 부분으로 구성됩니다. 컴포넌트 스크립트컴포넌트 템플릿입니다. 각 부분은 서로 다른 작업을 수행하지만, 함께 사용하면 사용하기 쉽고 빌드하려는 모든 것을 처리할 수 있을 만큼 표현력이 풍부한 프레임워크를 제공합니다.

src/components/EmptyComponent.astro
---
// 컴포넌트 스크립트 (JavaScript)
---
<!-- 컴포넌트 템플릿 (HTML + JS 표현식) -->

Astro는 코드 펜스 (---)를 사용하여 Astro 컴포넌트에서 컴포넌트 스크립트를 식별합니다. Markdown을 작성해 본 적이 있다면 프런트매터라는 유사한 개념에 이미 익숙할 수 있습니다. Astro의 컴포넌트 스크립트 아이디어는 이 개념에서 직접 영감을 받았습니다.

컴포넌트 스크립트를 사용하여 템플릿을 렌더링하는 데 필요한 모든 JavaScript 코드를 작성할 수 있습니다. 여기에는 다음이 포함될 수 있습니다.

  • 다른 Astro 컴포넌트 가져오기
  • React와 같은 다른 프레임워크 컴포넌트 가져오기
  • JSON 파일과 같은 데이터 가져오기
  • API 또는 데이터베이스에서 콘텐츠 가져오기
  • 템플릿에서 참조할 변수 생성
src/components/MyComponent.astro
---
import SomeAstroComponent from '../components/SomeAstroComponent.astro';
import SomeReactComponent from '../components/SomeReactComponent.jsx';
import someData from '../data/pokemon.json';
// `<X title="Hello, World" />`와 같이 전달된 컴포넌트 props에 접근합니다.
const { title } = Astro.props;
// 비공개 API 또는 데이터베이스에서 외부 데이터를 가져옵니다.
const data = await fetch('SOME_SECRET_API_URL/users').then(r => r.json());
---
<!-- 여기에 템플릿을 작성합니다! -->

코드 펜스는 작성한 JavaScript가 “펜스 안에” 있도록 보장하도록 설계되었습니다. 프런트엔드 애플리케이션으로 탈출하거나 사용자 손에 들어가지 않습니다. 사용자 브라우저에 표시될 염려 없이 비용이 많이 들거나 민감한 코드 (예: 비공개 데이터베이스 호출)를 안전하게 작성할 수 있습니다.

컴포넌트 템플릿은 코드 펜스 아래에 있으며 컴포넌트의 HTML 출력을 결정합니다.

여기에 일반 HTML을 작성하면 컴포넌트를 가져와 사용되는 모든 Astro 페이지에서 해당 HTML이 렌더링됩니다.

그러나 Astro의 컴포넌트 템플릿 구문JavaScript 표현식, Astro <style><script> 태그, 가져온 컴포넌트특수 Astro 지시어를 지원합니다. 컴포넌트 스크립트에서 정의된 데이터와 값은 컴포넌트 템플릿에서 동적으로 HTML을 생성하는 데 사용할 수 있습니다.

src/components/MyFavoritePokemon.astro
---
// 여기에 컴포넌트 스크립트를 작성합니다!
import Banner from '../components/Banner.astro';
import Avatar from '../components/Avatar.astro';
import ReactPokemonComponent from '../components/ReactPokemonComponent.jsx';
const myFavoritePokemon = [/* ... */];
const { title } = Astro.props;
---
<!-- HTML 주석을 지원합니다! -->
{/* JS 주석 구문도 유효합니다! */}
<Banner />
<h1>Hello, world!</h1>
<!-- 컴포넌트 스크립트의 props 및 기타 변수 사용 -->
<p>{title}</p>
<!-- 컴포넌트 렌더링을 지연시키고 대체 로딩 콘텐츠 제공 -->
<Avatar server:defer>
<svg slot="fallback" class="generic-avatar" transition:name="avatar">...</svg>
</Avatar>
<!-- `client:` 지시어를 사용하여 다른 UI 프레임워크 컴포넌트를 포함하고 하이드레이션합니다. -->
<ReactPokemonComponent client:visible />
<!-- JSX와 유사하게 HTML과 JavaScript 표현식을 혼합합니다. -->
<ul>
{myFavoritePokemon.map((data) => <li>{data.name}</li>)}
</ul>
<!-- 템플릿 지시어를 사용하여 여러 문자열 또는 객체에서 클래스 이름을 빌드합니다! -->
<p class:list={["add", "dynamic", { classNames: true }]} />

컴포넌트는 재사용 가능하고 구성 가능하도록 설계되었습니다. 컴포넌트 내부에서 다른 컴포넌트를 사용하여 점점 더 발전된 UI를 구축할 수 있습니다. 예를 들어, Button 컴포넌트를 사용하여 ButtonGroup 컴포넌트를 만들 수 있습니다.

src/components/ButtonGroup.astro
---
import Button from './Button.astro';
---
<div>
<Button title="Button 1" />
<Button title="Button 2" />
<Button title="Button 3" />
</div>

Astro 컴포넌트는 props를 정의하고 받을 수 있습니다. 이러한 props는 컴포넌트 템플릿에서 HTML 렌더링에 사용할 수 있습니다. Props는 프런트매터 스크립트의 Astro.props 전역에서 사용할 수 있습니다.

다음은 greeting prop과 name prop을 받는 컴포넌트의 예입니다. 받을 props는 전역 Astro.props 객체에서 구조 분해됩니다.

src/components/GreetingHeadline.astro
---
// 사용: <GreetingHeadline greeting="Howdy" name="Partner" />
const { greeting, name } = Astro.props;
---
<h2>{greeting}, {name}!</h2>

이 컴포넌트를 다른 Astro 컴포넌트, 레이아웃 또는 페이지에서 가져와 렌더링할 때 이러한 props를 속성으로 전달할 수 있습니다.

src/components/GreetingCard.astro
---
import GreetingHeadline from './GreetingHeadline.astro';
const name = 'Astro';
---
<h1>Greeting Card</h1>
<GreetingHeadline greeting="Hi" name={name} />
<p>I hope you have a wonderful day!</p>

Props 타입 인터페이스를 사용하여 TypeScript로 props를 정의할 수도 있습니다. Astro는 프런트매터에서 Props 인터페이스를 자동으로 인식하고 타입 경고/오류를 표시합니다. 이러한 props는 Astro.props에서 구조 분해될 때 기본값을 지정할 수도 있습니다.

src/components/GreetingHeadline.astro
---
interface Props {
name: string;
greeting?: string;
}
const { greeting = "Hello", name } = Astro.props;
---
<h2>{greeting}, {name}!</h2>

컴포넌트 props가 제공되지 않은 경우 사용할 기본값을 지정할 수 있습니다.

src/components/GreetingHeadline.astro
---
const { greeting = "Hello", name = "Astronaut" } = Astro.props;
---
<h2>{greeting}, {name}!</h2>

<slot /> 요소는 외부 HTML 콘텐츠의 자리 표시자이며, 다른 파일의 자식 요소를 컴포넌트 템플릿에 주입 (또는 “슬롯”)할 수 있도록 합니다.

기본적으로 컴포넌트에 전달된 모든 자식 요소는 <slot />에서 렌더링됩니다.

src/components/Wrapper.astro
---
import Header from './Header.astro';
import Logo from './Logo.astro';
import Footer from './Footer.astro';
const { title } = Astro.props;
---
<div id="content-wrapper">
<Header />
<Logo />
<h1>{title}</h1>
<slot /> <!-- 자식 요소가 여기에 렌더링됩니다. -->
<Footer />
</div>
src/pages/fred.astro
---
import Wrapper from '../components/Wrapper.astro';
---
<Wrapper title="Fred's Page">
<h2>All about Fred</h2>
<p>Here is some stuff about Fred.</p>
</Wrapper>

이 패턴은 Astro 레이아웃 컴포넌트의 기본입니다: 전체 HTML 콘텐츠 페이지를 <SomeLayoutComponent></SomeLayoutComponent> 태그로 “래핑”하여 컴포넌트에 전송하면 해당 컴포넌트에 정의된 공통 페이지 요소 내부에 렌더링됩니다.

Astro 컴포넌트는 명명된 슬롯을 가질 수도 있습니다. 이를 통해 해당 슬롯 이름이 있는 HTML 요소만 슬롯 위치로 전달할 수 있습니다.

슬롯은 name 속성을 사용하여 이름이 지정됩니다.

src/components/Wrapper.astro
---
import Header from './Header.astro';
import Logo from './Logo.astro';
import Footer from './Footer.astro';
const { title } = Astro.props;
---
<div id="content-wrapper">
<Header />
<!-- `slot="after-header"` 속성을 가진 자식 요소가 여기에 렌더링됩니다. -->
<slot name="after-header" />
<Logo />
<h1>{title}</h1>
<!-- `slot` 속성이 없거나, `slot="default"` 속성을 가진 자식 요소가 여기에 렌더링됩니다. -->
<slot />
<Footer />
<!-- `slot="after-footer"` 속성을 가진 자식 요소가 여기에 렌더링됩니다. -->
<slot name="after-footer" />
</div>

특정 슬롯에 HTML 콘텐츠를 삽입하려면 자식 요소에서 slot 속성을 사용하여 슬롯 이름을 지정합니다. 컴포넌트의 다른 모든 자식 요소는 기본 (이름 없는) <slot />에 삽입됩니다.

src/pages/fred.astro
---
import Wrapper from '../components/Wrapper.astro';
---
<Wrapper title="Fred's Page">
<img src="https://my.photo/fred.jpg" slot="after-header" />
<h2>All about Fred</h2>
<p>Here is some stuff about Fred.</p>
<p slot="after-footer">Copyright 2022</p>
</Wrapper>

래핑하는 <div> 없이 여러 HTML 요소를 컴포넌트의 <slot/> 자리 표시자로 전달하려면 Astro의 <Fragment/> 컴포넌트에서 slot="" 속성을 사용하세요.

src/components/CustomTable.astro
---
// 헤더 및 본문 콘텐츠를 위한 명명된 슬롯 자리 표시자가 있는 사용자 지정 테이블을 만듭니다.
---
<table class="bg-white">
<thead class="sticky top-0 bg-white"><slot name="header" /></thead>
<tbody class="[&_tr:nth-child(odd)]:bg-gray-100"><slot name="body" /></tbody>
</table>

slot="" 속성을 사용하여 "header""body" 콘텐츠를 지정하여 여러 행과 열의 HTML 콘텐츠를 삽입합니다. 개별 HTML 요소의 스타일을 지정할 수도 있습니다.

src/components/StockTable.astro
---
import CustomTable from './CustomTable.astro';
---
<CustomTable>
<Fragment slot="header"> <!-- 테이블 헤더를 전달합니다. -->
<tr><th>Product name</th><th>Stock units</th></tr>
</Fragment>
<Fragment slot="body"> <!-- 테이블 본문을 전달합니다. -->
<tr><td>Flip-flops</td><td>64</td></tr>
<tr><td>Boots</td><td>32</td></tr>
<tr><td>Sneakers</td><td class="text-red-500">0</td></tr>
</Fragment>
</CustomTable>

명명된 슬롯은 반드시 컴포넌트의 바로 아래 자식이어야 합니다. 중첩된 요소를 통해 명명된 슬롯을 전달할 수 없습니다.

슬롯은 대체 콘텐츠를 렌더링할 수도 있습니다. 슬롯에 일치하는 자식이 전달되지 않으면 <slot /> 요소는 자체 자리 표시자 자식을 렌더링합니다.

src/components/Wrapper.astro
---
import Header from './Header.astro';
import Logo from './Logo.astro';
import Footer from './Footer.astro';
const { title } = Astro.props;
---
<div id="content-wrapper">
<Header />
<Logo />
<h1>{title}</h1>
<slot>
<p>자식 요소가 슬롯에 전달되지 않으면 이 대체 콘텐츠가 표시됩니다.</p>
</slot>
<Footer />
</div>

대체 콘텐츠는 slot="name" 속성이 있는 일치하는 요소가 명명된 슬롯으로 전달되지 않을 때만 표시됩니다.

Astro는 슬롯 요소가 있지만 전달할 콘텐츠가 없을 때 빈 슬롯을 전달합니다. 빈 슬롯이 전달될 때 대체 콘텐츠를 기본값으로 사용할 수 없습니다. 대체 콘텐츠는 슬롯 요소를 찾을 수 없을 때만 표시됩니다.

슬롯은 다른 컴포넌트로 전달될 수 있습니다. 예를 들어, 중첩된 레이아웃을 만들 때:

src/layouts/BaseLayout.astro
---
---
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width" />
<meta name="generator" content={Astro.generator} />
<slot name="head" />
</head>
<body>
<slot />
</body>
</html>
src/layouts/HomeLayout.astro
---
import BaseLayout from './BaseLayout.astro';
---
<BaseLayout>
<slot name="head" slot="head" />
<slot />
</BaseLayout>

이제 HomeLayout에 전달된 기본 슬롯과 head 슬롯은 부모인 BaseLayout으로 전달됩니다.

src/pages/index.astro
---
import HomeLayout from '../layouts/HomeLayout.astro';
---
<HomeLayout>
<title slot="head">Astro</title>
<h1>Astro</h1>
</HomeLayout>

Astro는 .html 파일을 컴포넌트로 가져와 사용하거나 이러한 파일을 src/pages/ 하위 디렉터리에 페이지로 배치하는 것을 지원합니다. 프레임워크 없이 빌드된 기존 사이트의 코드를 재사용하거나 컴포넌트에 동적 기능이 없는 경우 HTML 컴포넌트를 사용할 수 있습니다.

HTML 컴포넌트는 유효한 HTML만 포함해야 하므로 다음과 같은 주요 Astro 컴포넌트 기능이 없습니다.

  • 프런트매터, 서버 측 가져오기 또는 동적 표현식을 지원하지 않습니다.
  • 모든 <script> 태그는 번들되지 않은 상태로 유지되며 is:inline이 있는 것처럼 처리됩니다.
  • public/ 폴더에 있는 자산만 참조할 수 있습니다.
Astro 프로젝트에서 UI 프레임워크 컴포넌트를 사용하는 방법에 대해 자세히 알아보세요.
기여하기 커뮤니티 후원하기