Back to Withastro

Build your first Astro island

src/content/docs/en/tutorial/6-islands/1.mdx

latest7.1 KB
Original Source

import Box from '/components/tutorial/Box.astro'; import Checklist from '/components/Checklist.astro'; import Spoiler from '/components/Spoiler.astro'; import MultipleChoice from '/components/tutorial/MultipleChoice.astro'; import Option from '/components/tutorial/Option.astro'; import PreCheck from '/components/tutorial/PreCheck.astro'; import PackageManagerTabs from '~/components/tabs/PackageManagerTabs.astro'; import { Steps } from '@astrojs/starlight/components';

Use a Preact component to greet your visitors with a randomly-selected welcome message!

<PreCheck> - Add Preact to your Astro project - Include Astro islands (Preact `.jsx` components) on your home page - Use `client:` directives to make islands interactive </PreCheck>

Add Preact to your Astro project

<Steps> 1. If it’s running, quit the dev server to have access to the terminal (keyboard shortcut: <kbd>Ctrl + C</kbd>).
  1. Add the ability to use Preact components in your Astro project with a single command:

    <PackageManagerTabs> <Fragment slot="npm"> ```sh npx astro add preact ``` </Fragment> <Fragment slot="pnpm"> ```sh pnpm astro add preact ``` </Fragment> <Fragment slot="yarn"> ```sh yarn astro add preact ``` </Fragment> </PackageManagerTabs>
  2. Follow the command line instructions to confirm adding Preact to your project.

    </Steps>

Include a Preact greeting banner

This component will take an array of greeting messages as a prop and randomly select one of them to show as a welcome message. The user can click a button to get a new random message.

<Steps> 1. Create a new file in `src/components/` named `Greeting.jsx`
Note the `.jsx` file extension. This file will be written in Preact, not Astro.

2. Add the following code to Greeting.jsx:

```jsx title="src/components/Greeting.jsx"
import { useState } from 'preact/hooks';

export default function Greeting({messages}) {

  const randomMessage = () => messages[(Math.floor(Math.random() * messages.length))];
  
  const [greeting, setGreeting] = useState(messages[0]);

  return (
    <div> 
      <h3>{greeting}! Thank you for visiting!</h3>
      <button onClick={() => setGreeting(randomMessage())}>
        New Greeting
      </button>
    </div>
  );
}
```

3. Import and use this component on your Home page index.astro.

```astro title="src/pages/index.astro" ins={3,8}
---
import BaseLayout from '../layouts/BaseLayout.astro';
import Greeting from '../components/Greeting';
const pageTitle = "Home Page";
---
<BaseLayout pageTitle={pageTitle}>
  <h2>My awesome blog subtitle</h2>
  <Greeting messages={["Hi", "Hello", "Howdy", "Hey there"]} />
</BaseLayout>
```

Check the preview in your browser: you should see a random greeting, but the button won't work!

4. Add a second <Greeting /> component with the client:load directive.

```astro title="src/pages/index.astro" ins={9} "client:load"
---
import BaseLayout from '../layouts/BaseLayout.astro';
import Greeting from '../components/Greeting';
const pageTitle = "Home Page";
---
<BaseLayout pageTitle={pageTitle}>
  <h2>My awesome blog subtitle</h2>
  <Greeting messages={["Hi", "Hello", "Howdy", "Hey there"]} />
  <Greeting client:load messages={["Hej", "Hallo", "Hola", "Habari"]} />
</BaseLayout>
```

5. Revisit your page and compare the two components. The second button works because the client:load directive tells Astro to send and rerun its JavaScript on the client when the page loads, making the component interactive. This is called a hydrated component.

  1. Once the difference is clear, remove the non-hydrated Greeting component.

    astro
    ---
    import BaseLayout from '../layouts/BaseLayout.astro';
    import Greeting from '../components/Greeting';
    const pageTitle = "Home Page";
    ---
    <BaseLayout pageTitle={pageTitle}>
      <h2>My awesome blog subtitle</h2>
      <Greeting messages={["Hi", "Hello", "Howdy", "Hey there"]} />
      <Greeting client:load messages={["Hej", "Hallo", "Hola", "Habari"]} />
    </BaseLayout>
    
</Steps> <Box icon="question-mark">

Analyze the Pattern

There are other client: directives to explore. Each sends the JavaScript to the client at a different time. client:visible, for example, will only send the component's JavaScript when it is visible on the page.

Consider an Astro component with the following code:

astro
---
import BaseLayout from '../layouts/BaseLayout.astro';
import AstroBanner from '../components/AstroBanner.astro';
import PreactBanner from '../components/PreactBanner';
import SvelteCounter from '../components/SvelteCounter.svelte';
---
<BaseLayout>
  <AstroBanner />
  <PreactBanner />
  <PreactBanner client:load />
  <SvelteCounter />
  <SvelteCounter client:visible />
</BaseLayout>
  1. Which of the five components will be hydrated islands, sending JavaScript to the client?

    <p> <Spoiler>`<PreactBanner client:load />` and `<SvelteCounter client:visible />` will be hydrated islands.</Spoiler> </p>
  2. In what way(s) will the two <PreactBanner /> components be the same? In what way(s) will they be different?

    <p> <Spoiler>**Same**: They both show the same HTML elements and look the same initially. **Different**: The component with the `client:load` directive will rerender after the page is loaded, and any interactive elements that it has will work.</Spoiler> </p>
  3. Assume the SvelteCounter component shows a number and has a button to increase it. If you couldn't see your website's code, only the live published page, how would you tell which of the two <SvelteCounter /> components used client:visible?

    <p> <Spoiler>Try clicking the button, and see which one is interactive. If it responds to your input, it must have had a `client:` directive.</Spoiler> </p>
</Box> <Box icon="question-mark">

Test your knowledge

For each of the following components, identify what will be sent to the browser:

  1. <ReactCounter client:load />

    <MultipleChoice> <Option> HTML and CSS only </Option> <Option isCorrect> HTML, CSS, and JavaScript </Option> </MultipleChoice>
  2. <SvelteCard />

    <MultipleChoice> <Option isCorrect> HTML and CSS only </Option> <Option> HTML, CSS, and JavaScript </Option> </MultipleChoice>
</Box> <Box icon="check-list">

Checklist

<Checklist> - [ ] I can install an Astro integration. - [ ] I can write UI framework components in their own language. - [ ] I can use a `client:` directive for hydration on my UI framework component. </Checklist> </Box>

Resources