컴포넌트
Astro 컴포넌트는 모든 Astro 프로젝트의 기본 구성 요소입니다. 클라이언트 측 런타임이 없는 HTML 전용 템플릿 컴포넌트이며 .astro
파일 확장자를 사용합니다.
HTML을 알고 있다면 이미 첫 번째 Astro 컴포넌트를 작성하는 데 필요한 것을 충분히 알고 있는 것입니다.
Astro 컴포넌트는 매우 유연합니다. Astro 컴포넌트는 SEO 작업을 쉽게 만들어주는 공통 <meta>
태그 모음과 같은 작은 HTML 스니펫만큼 작을 수 있습니다. 컴포넌트는 헤더나 프로필 카드와 같은 재사용 가능한 UI 요소가 될 수 있습니다. Astro 컴포넌트는 전체 페이지 레이아웃을 포함할 수도 있으며, 특수한 src/pages/
폴더에 위치할 경우 전체 페이지 자체가 될 수도 있습니다.
Astro 컴포넌트의 가장 중요한 점은 클라이언트에서 렌더링되지 않는다는 것입니다. 빌드 타임 또는 요청 시 HTML로 렌더링됩니다. 컴포넌트 프런트매터에 JavaScript 코드를 포함할 수 있으며, 이 모든 코드는 사용자 브라우저로 전송되는 최종 페이지에서 제거됩니다. 그 결과, 기본적으로 추가되는 JavaScript 부하가 전혀 없는 더 빠른 사이트가 됩니다.
Astro 컴포넌트에 클라이언트 측 상호 작용이 필요한 경우, 표준 HTML <script>
태그 또는 UI 프레임워크 컴포넌트를 “클라이언트 아일랜드”로 추가할 수 있습니다.
개인화되거나 동적인 콘텐츠를 렌더링해야 하는 컴포넌트의 경우, 서버 지시어를 추가하여 서버 렌더링을 연기할 수 있습니다. 이러한 “서버 아일랜드”는 전체 페이지 로드를 지연시키지 않고 사용 가능한 시점에 콘텐츠를 렌더링합니다.
컴포넌트 구조
섹션 제목: 컴포넌트 구조Astro 컴포넌트는 두 가지 주요 부분으로 구성됩니다. 컴포넌트 스크립트와 컴포넌트 템플릿입니다. 각 부분은 서로 다른 작업을 수행하지만, 함께 사용하면 사용하기 쉽고 빌드하려는 모든 것을 처리할 수 있을 만큼 표현력이 풍부한 프레임워크를 제공합니다.
---// 컴포넌트 스크립트 (JavaScript)---<!-- 컴포넌트 템플릿 (HTML + JS 표현식) -->
컴포넌트 스크립트
섹션 제목: 컴포넌트 스크립트Astro는 코드 펜스 (---
)를 사용하여 Astro 컴포넌트에서 컴포넌트 스크립트를 식별합니다. Markdown을 작성해 본 적이 있다면 프런트매터라는 유사한 개념에 이미 익숙할 수 있습니다. Astro의 컴포넌트 스크립트 아이디어는 이 개념에서 직접 영감을 받았습니다.
컴포넌트 스크립트를 사용하여 템플릿을 렌더링하는 데 필요한 모든 JavaScript 코드를 작성할 수 있습니다. 여기에는 다음이 포함될 수 있습니다.
- 다른 Astro 컴포넌트 가져오기
- React와 같은 다른 프레임워크 컴포넌트 가져오기
- JSON 파일과 같은 데이터 가져오기
- API 또는 데이터베이스에서 콘텐츠 가져오기
- 템플릿에서 참조할 변수 생성
---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가 “펜스 안에” 있도록 보장하도록 설계되었습니다. 프런트엔드 애플리케이션으로 탈출하거나 사용자 손에 들어가지 않습니다. 사용자 브라우저에 표시될 염려 없이 비용이 많이 들거나 민감한 코드 (예: 비공개 데이터베이스 호출)를 안전하게 작성할 수 있습니다.
Astro 컴포넌트 스크립트는 TypeScript이며, 이를 통해 편집기 도구 및 오류 검사를 위해 JavaScript에 구문을 추가할 수 있습니다.
컴포넌트 템플릿
섹션 제목: 컴포넌트 템플릿컴포넌트 템플릿은 코드 펜스 아래에 있으며 컴포넌트의 HTML 출력을 결정합니다.
여기에 일반 HTML을 작성하면 컴포넌트를 가져와 사용되는 모든 Astro 페이지에서 해당 HTML이 렌더링됩니다.
그러나 Astro의 컴포넌트 템플릿 구문은 JavaScript 표현식, Astro <style>
및 <script>
태그, 가져온 컴포넌트 및 특수 Astro 지시어를 지원합니다. 컴포넌트 스크립트에서 정의된 데이터와 값은 컴포넌트 템플릿에서 동적으로 HTML을 생성하는 데 사용할 수 있습니다.
---// 여기에 컴포넌트 스크립트를 작성합니다!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
컴포넌트를 만들 수 있습니다.
---import Button from './Button.astro';---<div> <Button title="Button 1" /> <Button title="Button 2" /> <Button title="Button 3" /></div>
컴포넌트 Props
섹션 제목: 컴포넌트 PropsAstro 컴포넌트는 props를 정의하고 받을 수 있습니다. 이러한 props는 컴포넌트 템플릿에서 HTML 렌더링에 사용할 수 있습니다. Props는 프런트매터 스크립트의 Astro.props
전역에서 사용할 수 있습니다.
다음은 greeting
prop과 name
prop을 받는 컴포넌트의 예입니다. 받을 props는 전역 Astro.props
객체에서 구조 분해됩니다.
---// 사용: <GreetingHeadline greeting="Howdy" name="Partner" />const { greeting, name } = Astro.props;---<h2>{greeting}, {name}!</h2>
이 컴포넌트를 다른 Astro 컴포넌트, 레이아웃 또는 페이지에서 가져와 렌더링할 때 이러한 props를 속성으로 전달할 수 있습니다.
---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
에서 구조 분해될 때 기본값을 지정할 수도 있습니다.
---interface Props { name: string; greeting?: string;}
const { greeting = "Hello", name } = Astro.props;---<h2>{greeting}, {name}!</h2>
컴포넌트 props가 제공되지 않은 경우 사용할 기본값을 지정할 수 있습니다.
---const { greeting = "Hello", name = "Astronaut" } = Astro.props;---<h2>{greeting}, {name}!</h2>
<slot />
요소는 외부 HTML 콘텐츠의 자리 표시자이며, 다른 파일의 자식 요소를 컴포넌트 템플릿에 주입 (또는 “슬롯”)할 수 있도록 합니다.
기본적으로 컴포넌트에 전달된 모든 자식 요소는 <slot />
에서 렌더링됩니다.
Astro.props
를 통해 컴포넌트 전체에서 사용할 수 있도록 Astro 컴포넌트에 전달되는 속성인 props와 달리, 슬롯은 작성된 위치에 자식 HTML 요소를 렌더링합니다.
---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>
---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
속성을 사용하여 이름이 지정됩니다.
---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 />
에 삽입됩니다.
---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>
컴포넌트의 <slot name="my-slot" />
자리 표시자로 전달하려는 자식 요소에 slot="my-slot"
속성을 사용합니다.
래핑하는 <div>
없이 여러 HTML 요소를 컴포넌트의 <slot/>
자리 표시자로 전달하려면 Astro의 <Fragment/>
컴포넌트에서 slot=""
속성을 사용하세요.
---// 헤더 및 본문 콘텐츠를 위한 명명된 슬롯 자리 표시자가 있는 사용자 지정 테이블을 만듭니다.---<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 요소의 스타일을 지정할 수도 있습니다.
---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>
명명된 슬롯은 반드시 컴포넌트의 바로 아래 자식이어야 합니다. 중첩된 요소를 통해 명명된 슬롯을 전달할 수 없습니다.
명명된 슬롯은 UI 프레임워크 컴포넌트에도 전달할 수 있습니다!
Astro 슬롯 이름을 동적으로 생성하는 것은 불가능합니다 (예: map 함수 내에서). UI 프레임워크 컴포넌트에서 이 기능이 필요한 경우, 프레임워크 자체에서 이러한 동적 슬롯을 생성하는 것이 가장 좋습니다.
슬롯의 대체 콘텐츠
섹션 제목: 슬롯의 대체 콘텐츠슬롯은 대체 콘텐츠를 렌더링할 수도 있습니다. 슬롯에 일치하는 자식이 전달되지 않으면 <slot />
요소는 자체 자리 표시자 자식을 렌더링합니다.
---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는 슬롯 요소가 있지만 전달할 콘텐츠가 없을 때 빈 슬롯을 전달합니다. 빈 슬롯이 전달될 때 대체 콘텐츠를 기본값으로 사용할 수 없습니다. 대체 콘텐츠는 슬롯 요소를 찾을 수 없을 때만 표시됩니다.
슬롯 전달
섹션 제목: 슬롯 전달슬롯은 다른 컴포넌트로 전달될 수 있습니다. 예를 들어, 중첩된 레이아웃을 만들 때:
------<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>
---import BaseLayout from './BaseLayout.astro';---<BaseLayout> <slot name="head" slot="head" /> <slot /></BaseLayout>
<slot />
태그에서 name
과 slot
속성을 모두 사용하여 명명된 슬롯을 다른 컴포넌트로 전달할 수 있습니다.
이제 HomeLayout
에 전달된 기본 슬롯과 head
슬롯은 부모인 BaseLayout
으로 전달됩니다.
---import HomeLayout from '../layouts/HomeLayout.astro';---<HomeLayout> <title slot="head">Astro</title> <h1>Astro</h1></HomeLayout>
HTML 컴포넌트
섹션 제목: HTML 컴포넌트Astro는 .html
파일을 컴포넌트로 가져와 사용하거나 이러한 파일을 src/pages/
하위 디렉터리에 페이지로 배치하는 것을 지원합니다. 프레임워크 없이 빌드된 기존 사이트의 코드를 재사용하거나 컴포넌트에 동적 기능이 없는 경우 HTML 컴포넌트를 사용할 수 있습니다.
HTML 컴포넌트는 유효한 HTML만 포함해야 하므로 다음과 같은 주요 Astro 컴포넌트 기능이 없습니다.
- 프런트매터, 서버 측 가져오기 또는 동적 표현식을 지원하지 않습니다.
- 모든
<script>
태그는 번들되지 않은 상태로 유지되며is:inline
이 있는 것처럼 처리됩니다. public/
폴더에 있는 자산만 참조할 수 있습니다.
HTML 컴포넌트의 <slot />
요소는 Astro 컴포넌트에서와 같이 작동합니다. 대신 HTML 웹 컴포넌트 슬롯 요소를 사용하려면 <slot>
요소에 is:inline
을 추가하세요.