Jack Harrhy
Workshops/2025

Astro-Workshop

This page was used for misc. links during the live workshop I did in June of 2025 on Astro!

The complete StackBlitz example (with some stuff I didn’t end up getting to in the workshop portion) is available here.

They’ll probably lack context without my words next to them, but here are the slides from the introduction:


Links from the live talk:

1: https://astro.build/

2: https://astro.new/

3: https://github.com/ascorbic/astro-loaders/tree/main/packages/feed

4: https://jackharrhy.dev/linkblog/rss.xml

5: https://pokeapi.co/api/v2/pokemon/ditto

import { useState, useEffect, useRef } from 'react';

export default function PokemonSearch() {
  const [term, setTerm] = useState('');
  const [pokemon, setPokemon] = useState(null);
  const debounce = useRef();

  useEffect(() => {
    if (!term) {
      setPokemon(null);
      return;
    }

    clearTimeout(debounce.current);
    debounce.current = setTimeout(async () => {
      try {
        const res = await fetch(
          `https://pokeapi.co/api/v2/pokemon/${term.toLowerCase()}`
        );
        if (!res.ok) throw new Error();
        const data = await res.json();

        setPokemon({
          name: data.name,
          type: data.types.map((t) => t.type.name).join(', '),
          img: data.sprites.front_default,
        });
      } catch {
        setPokemon(null);
      }
    }, 300);

    return () => clearTimeout(debounce.current);
  }, [term]);

  return (
    <div className="pokemon-search">
      <input
        value={term}
        onChange={(e) => setTerm(e.target.value)}
        placeholder="Search Pokémon"
      />

      {pokemon && (
        <div className="result">
          <h2 className="capitalize">{pokemon.name}</h2>
          <p>Type: {pokemon.type}</p>
          {pokemon.img && (
            <img src={pokemon.img} alt={pokemon.name} width={96} height={96} />
          )}
        </div>
      )}
    </div>
  );
}