¬°Estamos en directo en Twitch!

¬°Entra y participa!

Imagen de la etiqueta svelte

Declaraciones reactivas y fetching de datos con Svelte

¬∑ 6 minutos de lectura ¬∑ ¬ŅUna errata? Edita el art√≠culo

Ya dominamos c√≥mo crear componentes y gestionar el estado de los mismos gracias a las asignaciones reactivas es el momento de ejecutar c√≥digo cada vez que este estado cambie. Para ello, vamos a conocer c√≥mo crear declaraciones reactivas y, al final, conseguiremos hacer fetch de datos de una API. Si no te gusta leer, te dejo mi canal de Youtube ūüĎá donde he subido la misma explicaci√≥n en v√≠deo.

Reactividad en Svelte: los límites de inferir

Cuando hablamos de inferir, hablamos de cómo Svelte, a partir del código, es capaz de detectar si una variable es un estado del componente, tal y como habíamos visto en el artículo anterior.

Ahora, ¬Ņqu√© pasa si queremos utilizar ese estado para calcular una variable? Por ejemplo, imaginemos que queremos utilizar un estado inferido de counter para crear una variable que nos muestre si el n√ļmero es par o impar.

<script>
 let counter = 2;
 let isEvenMessage = counter % 2 === 0 ? 'Is Even' : 'Is Odd'

 const handleClick = () => counter++
</script>

<button on:click={handleClick}>Incrementar</button>
<span>{counter}</span>
<span>{isEvenMessage}</span>

Como counter se inicia a 2, al principio el mensaje es Is Odd pero… si hacemos click en el bot√≥n, el counter se incrementa en 3 pero, sin embargo, el mensaje que vemos todav√≠a es Is Even, lo que significa que no est√° mostrando el mensaje correcto. ¬ŅPor qu√©?

Lo que est√° ocurriendo es que la variable isEvenMessage s√≥lo se est√° evaluando una vez. A diferencia de la variable counter que Svelte s√≠ est√° infiriendo que es un estado. Esto es un error muy com√ļn a la hora de trabajar con Svelte, ya que uno podr√≠a esperar que la variable isEvenMessage fuese a re-asignarse de forma autom√°tica cuando no es as√≠.

Ahora que ya lo sabemos. ¬ŅC√≥mo podemos arreglarlo? Tenemos dos formas. La primera, mover la evaluaci√≥n al render, en lugar de hacerlo dentro de las etiquetas <script>. As√≠, esto siempre se evaluar√° en cada renderizado y mostrar√° la informaci√≥n correcta.

<script>
 let counter = 2;

 const handleClick = () => counter++
</script>

<button on:click={handleClick}>Incrementar</button>
<span>{counter}</span>
<span>{counter % 2 === 0 ? 'Is Even' : 'Is Odd'}</span>

Esta opción es bastante sencilla, pero Svelte ofrece otra forma que nos desbloqueará un montón de posibilidades y es utilizar el símbolo especial $ para indicar que la declaración es reactiva:

<script>
 let counter = 2;
 let isEvenMessage;
 // al usar $ le decimos que esta declaración
 // se tiene que ejecutar de forma reactiva
 $: isEvenMessage = counter % 2 === 0 ? 'Is Even' : 'Is Odd'

 const handleClick = () => counter++
</script>

<button on:click={handleClick}>Incrementar</button>
<span>{counter}</span>
<span>{isEvenMessage}</span>

Con esto, si usamos el botón Incrementar, veremos que muestra el mensaje correcto. Lo que hace el símbolo $ es avisar a Svelte que esta sentencia es reactiva y el framework detectará dentro de esa declaración qué variables se están usando (en este caso counter) de forma que, cada vez que se actualice ese valor, pasará a ejecutar de nuevo la sentencia.

También es importante indicar que la declaración reactiva se ejecutará también nada más montar el componente, por eso vemos desde el principio un mensaje con la información.

Adem√°s, podemos a√Īadir tantas declaraciones reactivas como queramos. Por ejemplo, vamos a a√Īadir una que, lo que va a hacer, es no permitir que el counter pase de un valor m√°ximo y, para ello, vamos a ver c√≥mo conseguirlo a√Īadiendo una declaraci√≥n multil√≠nea:

<script>
 let counter = 2;

 $: isEvenMessage = counter % 2 === 0 ? 'Is Even' : 'Is Odd'

 // usando $, podemos a√Īadir declaraciones completas si 
 $: {
   if (counter > 9) {
     counter = 9
   }
 }
 const handleClick = () => counter++
</script>

<button on:click={handleClick}>Incrementar</button>
<span>{counter}</span>
<span>{isEvenMessage}</span>

Las declaraciones reactivas pueden tener cláusulas de entrada por lo que podemos escribirlo de una manera todavía más limpia para conseguir el mismo resultado.

 $: if (counter > 9) {
  counter = 9
 }

De esta forma, esta declaración reactiva sólo se ejecutará cuando el valor del counter sea mayor a nueve. Al ejecutarse, la declaración hará que el estado local counter no pueda nunca sobrepasar el valor de 9.

Fetching de datos con Svelte

Ahora que ya dominamos las declaraciones reactivas, es el momento de conseguir hacer un fetching de datos con este framework. Para ello, vamos a crear un nuevo componente llamado Input que tendr√° una caja de texto donde podremos a√Īadir un texto a buscar.

<script>
  // donde guardamos el valor de la caja de texto
  let value = ''
  // escuchamos el evento `input` y ejecutamos
  // este método para actualizar el estado
  const handleInput = (event) =>
    value = event.target.value
</script>

<input value={value} on:input={handleInput}>

Dos cosas a decir sobre este componente. Primero, que en Svelte existe una mejor forma de realizar este tipo de actualizaciones de estado al escuchar eventos input y lo veremos m√°s adelante. Segundo, que por ahora, este componente no es muy √ļtil, ya que lo √ļnico que podemos hacer es escribir texto en la caja y ya est√°.

Ahora, utilizando una declaración reactiva, podríamos hacer el fetching de datos con el texto a buscar. Lo vamos a hacer utilizando la API de OMDB, para buscar películas. Podéis conseguir una API KEY muy fácilmente desde su página web. El endpoint es este:

`https://www.omdbapi.com/?s=${textoABuscar}&apikey=${apiKey}`

As√≠ que vamos a a√Īadir la declaraci√≥n reactiva que se ejecutar√° cada vez que el valor de value cambie y lo que haremos es llamar al endpoint de OMDB utilizando el m√©todo fetch de la siguiente forma.

<script>
  let value = ''

  const handleInput = (event) => value = event.target.value

  $: {
    fetch(`https://www.omdbapi.com/?s=${value}&apikey=422350ff`)
      .then(response => response.json())
      .then(apiResponse => {
        console.log(apiResponse)
      })
  }
</script>

<input value={value} on:input={handleInput}>

Ahora… esto no s√≥lo se ejecuta cada vez que cambiamos el texto en la caja… Como hab√≠amos visto anteriromente, tambi√©n se ejecuta la primera vez que se monta el componente. Para solucionar esto deber√≠amos ponerle alguna cl√°usula de entrada a la declaraci√≥n reactiva. La primera que se nos ocurre es la de evitar que haga una llamada a la API con un string vac√≠o.

$: if (value !== '') {
  fetch(`https://www.omdbapi.com/?s=${value}&apikey=422350ff`)
    .then(response => response.json())
    .then(apiResponse => {
      console.log(apiResponse)
    })
}

Pero esto también da problemas con las primeras letras, ya que hay demasiados resultados cuando intentas buscar una sola letra. Así que vamos a hacer que sólo empiece a buscar a partir de tres carácteres quedando todo nuestro código del componente así:

<script>
  let value = ''
  let results = []

  const handleInput = (event) => value = event.target.value

  $: if (value.length > 2) {
    fetch('https://www.omdbapi.com/?s=${value}&apikey=422350ff')
      .then(response => response.json())
      .then(apiResponse => {
        results = apiResponse.Search
        console.log(results)
      })
  }
</script>

<input value={value} on:input={handleInput}>

Conclusiones

Con este art√≠culo ya hemos visto c√≥mo podemos controlar del todo la reactividad en Svelte. Aunque las declaraciones reactivas no son tan m√°gicas como el state, ya que hay que a√Īadir un s√≠mbolo $, Svelte s√≠ que nos ayuda a detectar cuando estas declaraciones se tienen que ejecutar ya que detecta qu√© dependencias se est√°n usando dentro.

Adem√°s, hemos visto que nos permite poder a√Īadir condiciones de forma que s√≥lo se ejecuten cuando sea necesario. A mi personalmente me gusta mucho que la condici√≥n de entrada est√© arriba del todo, lo que lo hace muy legible y entendible. Ya sabes que me encanta React pero en este caso el useEffect es m√°s dif√≠cil de leer ya que las condiciones pueden ir en cualquier sitio y, adem√°s, las dependencias van en la √ļltima l√≠nea.

Con todo, al final, hemos hecho nuestra primera llamada fetch. En la próxima clase vamos a ver cómo podemos listar los resultados, indicar si está cargando y muchas cosas más. ¡Sigue la conversación en Twitter!

Contenido del artículo

Comparte el artículo