컨텐츠로 이동

컴포넌트

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

Astro 컴포넌트는 매우 유연합니다. Astro 컴포넌트에는 헤더나 프로필 카드와 같은 페이지에서 재사용 가능한 UI가 포함되는 경우가 많습니다. 때로는 Astro 컴포넌트에 SEO 작업을 쉽게 만들어주는 일반적인 <meta> 태그 모음과 같은 작은 HTML 조각이 포함될 수도 있습니다. Astro 컴포넌트에는 전체 페이지 레이아웃이 포함될 수도 있습니다.

Astro 컴포넌트에 대해 알아야 할 가장 중요한 점은 클라이언트에서 렌더링되지 않는다는 것입니다. 기본적으로 빌드 시 HTML로 렌더링되며, 서버 측 렌더링 (SSR)을 사용하는 경우 사용자의 요청을 받았을 때 HTML로 렌더링 됩니다. 컴포넌트 프런트매터에 JavaScript 코드를 포함할 수 있으며, 모든 내용은 사용자 브라우저로 전송되는 최종 페이지에서 제거됩니다. 그 결과 기본적으로 JavaScript가 추가되지 않아 사이트가 더 빨라집니다.

Astro 컴포넌트가 클라이언트 측에서 상호작용을 해야하는 경우, 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="안녕하세요!" />`와 같이 컴포넌트에 전달된 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 ReactPokemonComponent from '../components/ReactPokemonComponent.jsx';
const myFavoritePokemon = [/* ... */];
const { title } = Astro.props;
---
<!-- HTML 주석이 지원됩니다! -->
{/* JS 주석도 지원됩니다! */}
<Banner />
<h1>안녕하세요!</h1>
<!-- 컴포넌트 스크립트의 props 및 기타 변수를 사용합니다. -->
<p>{title}</p>
<!-- 수화를 위해 `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>인사 카드</h1>
<GreetingHeadline greeting="Hi" name={name} />
<p>좋은 하루 보내세요!</p>

TypeScript에서 Props 타입 인터페이스를 사용해 props를 정의할 수도 있습니다. Astro는 프런트매터에서 Props 인터페이스를 선택하고 타입 경고/오류를 제공합니다. 이 props는 Astro.props에서 구조 분해 할당될 때 기본값을 설정할 수도 있습니다.

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

컴포넌트 props에 아무 값도 전달하지 않으면 기본값이 사용됩니다.

src/components/GreetingHeadline.astro
---
const { greeting = "안녕하세요", 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>Fred에 대한 모든 것</h2>
<p>다음은 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 name="after-header"/> <!-- `slot="after-header"` 속성을 가진 하위 요소가 여기에 전달됩니다. -->
<Logo />
<h1>{title}</h1>
<slot /> <!-- `slot`이 없거나 `slot="default"` 속성을 가진 하위 요소가 여기에 전달됩니다. -->
<Footer />
<slot name="after-footer"/> <!-- `slot="after-footer"` 속성을 가진 하위 요소가 여기에 전달됩니다. -->
</div>

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

src/pages/fred.astro
---
import Wrapper from '../components/Wrapper.astro';
---
<Wrapper title="Fred의 페이지">
<img src="https://my.photo/fred.jpg" slot="after-header">
<h2>Fred의 모든 것</h2>
<p>다음은 Fred에 관한 내용입니다.</p>
<p slot="after-footer">Copyright 2023</p>
</Wrapper>

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

src/components/CustomTable.astro
---
// header 및 body 콘텐츠에 대한 명명된 슬롯이 있는 사용자 정의 테이블 생성
---
<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>

슬롯은 다른 컴포넌트로 전송될 수 있습니다. 예를 들어 중첩된 레이아웃을 생성하는 경우:

src/layouts/BaseLayout.astro
---
---
<html lang="ko">
<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 프레임워크 컴포넌트를 사용하는 방법에 대해 알아보세요.