@@ -37,27 +37,23 @@ const code = {
3737 <div data-ilha="pokedex"></div>
3838 ` ,
3939 script : dedent `
40- import ilha, { html, mount, type } from "ilha";
40+ import ilha, { html, mount, context } from "ilha";
41+
42+ const selectedPokemon = context("selectedPokemon", "charizard");
4143
4244 const pokemonPicker = ilha
43- .input(type<{ defaultPokemon: string }>())
44- .state("pokemon", ({ defaultPokemon }) => defaultPokemon)
4545 .state("pokemonList", [])
4646 .onMount(({ state }) => {
47- const fetchList = async () => {
48- const req = await fetch("https://pokeapi.co/api/v2/pokemon");
49- const list = await req.json();
50- state.pokemonList(list.results);
51- };
52- fetchList();
47+ fetch("https://pokeapi.co/api/v2/pokemon")
48+ .then((r) => r.json())
49+ .then((list) => state.pokemonList(list.results));
5350 })
54- .bind("#pokemon", "pokemon" )
51+ .bind("#pokemon", selectedPokemon )
5552 .render(({ state }) => {
56- const options = state
57- .pokemonList()
58- .map(({ name }) => html\`
59- <option value="\${name}">\${name}</option>
60- \`);
53+ const currentPokemon = selectedPokemon();
54+ const options = state.pokemonList().map(({ name }) =>
55+ html\`<option value="\${name}" \${name === currentPokemon ? "selected" : ""}>\${name}</option>\`
56+ );
6157 return html\`
6258 <label for="pokemon">Pick a Pokemon</label>
6359 <select id="pokemon">
@@ -67,24 +63,32 @@ const code = {
6763 });
6864
6965 const pokemonCard = ilha
70- .input(type<{ pokemon: string }>())
7166 .state("pokemonData", null)
72- .onMount(({ state, input }) => {
73- const fetchPokemon = async () => {
74- const req = await fetch(\`https://pokeapi.co/api/v2/pokemon/\${input.pokemon}\`);
75- const data = await req.json();
76- state.pokemonData(data);
77- };
78- fetchPokemon();
67+ .effect(({ state }) => {
68+ const controller = new AbortController();
69+ const pokemon = selectedPokemon();
70+ fetch(\`https://pokeapi.co/api/v2/pokemon/\${pokemon}\`, {
71+ signal: controller.signal,
72+ })
73+ .then((r) => r.json())
74+ .then((data) => {
75+ if (!controller.signal.aborted) {
76+ state.pokemonData(data);
77+ }
78+ })
79+ .catch((err) => {
80+ if (err.name !== 'AbortError') throw err;
81+ });
82+ return () => controller.abort();
7983 })
8084 .render(({ state }) => {
8185 if (!state.pokemonData()) return html\`<p>Loading...</p>\`;
8286 const { name, sprites, types } = state.pokemonData();
83- const typeBadges = types.map(({ type }) => html\`
84- <span class="badge">\${type.name}</span>
85- \` );
87+ const typeBadges = types.map(({ type }) =>
88+ html\` <span class="badge">\${type.name}</span>\`
89+ );
8690 return html\`
87- <img src="\${sprites.front_default}" />
91+ <img src="\${sprites.front_default}" alt="\${name}" />
8892 <h2>\${name}</h2>
8993 \${typeBadges}
9094 \`;
@@ -93,10 +97,9 @@ const code = {
9397 const pokedex = ilha
9498 .slot("picker", pokemonPicker)
9599 .slot("card", pokemonCard)
96- .state("selected", "charizard")
97- .render(({ slots, state }) => html\`
98- \${slots.picker({ defaultPokemon: state.selected() })}
99- \${slots.card({ pokemon: state.selected() })}
100+ .render(({ slots }) => html\`
101+ \${slots.picker()}
102+ \${slots.card()}
100103 \`);
101104
102105 mount({ pokedex });
0 commit comments