Svelte 3: Guia para o Desenvolvedor (React) Impaciente

oieduardorabelo

Eduardo Rabelo

Posted on July 21, 2019

Svelte 3: Guia para o Desenvolvedor (React) Impaciente

Tudo o que você precisa saber para começar com o Svelte 3!

Tabela de Conteúdo

  1. O que é Svelte?
  2. Para quem este guia é (requisitos)
  3. O que você vai aprender e construir
  4. Configurando o projeto
  5. Mergulhando em Svelte
  6. Buscando dados com Svelte
  7. Criando listas com "each"
  8. Passando "props"
  9. Múltiplas "props" e "spreading"
  10. Componentes filhos e "render props"
  11. Manipulando eventos e modificadores de eventos
  12. Uma rápida recapitulação
  13. Implementando o recurso de pesquisa
  14. Reatividade
  15. Comparando com React
  16. Como o Svelte se compara ao React e Vue?
  17. Mais Recursos
  18. Finalizando

1. O que é Svelte?

Svelte é uma biblioteca JavaScript de interface do usuário criada por Rich Harris. Rich acha que o DOM Virtual é apenas uma sobrecarga e apareceu com o Svelte, que agora está em sua terceira versão.

Mas por que você gostaria de aprender Svelte? React ou Vue não são o suficiente? Bem, existem alguns pontos interessantes:

  • Svelte é um compilador, não uma dependência como React ou Vue
  • O Svelte parece precisar de menos código para as mesmas coisas que o React, que exige 40% a mais de LOC (fonte: Rich Harris)
  • O Svelte não possui um DOM virtual, compila um JavaScript "vanilla" mínimo e parece ter um desempenho melhor que outras bibliotecas

Eu não fiz nenhum benchmark para confirmar essas coisas, fica a sua responsabilidade de pesquisar. No tutorial a seguir, vou focar nos conceitos básicos do Svelte 3.

De qualquer forma, não pule por este artigo muito rápido. Svelte 3 é realmente interessante, embora tenha algumas arestas. Enquanto isso, você pode mergulhar no Svelte 3 com este tutorial e formar sua própria opinião.

Bom proveito!

2. Para quem este guia é (requisitos)

Você não terá problemas em seguir o tutorial se tiver uma compreensão básica de:

  • HTML, CSS e JavaScript (ES6+)
  • Módulos ES6, sintaxe import/export
  • Sintaxe async/await
  • Conceitos sobre componentes
  • Sintaxe da API fetch

Se você está apenas começando, talvez o tutorial ainda seja demais para você. Mas não se desespere, confira os recursos a seguir e volte mais tarde.

Se você precisar de uma atualização nos módulos do ES6, consulte a documentação do import e export em JavaScript. Há também o excelente artigo ES6 Modules in Depth.

E para saber mais sobre a API fetch, confira Fetch API.

(Sim, é um monte de coisas para um novato saber. Não me culpe!).

Além disso, certifique-se de ter uma versão mais recente do Node.js instalada em seu sistema.

3. O que você vai aprender e construir

Nós não vamos construir uma aplicação "fullstack" neste tutorial. Ao invés disso, vou guiá-lo através dos conceitos básicos do Svelte 3, construindo algumas pequenas partes da interface do usuário. No final, você deve poder começar a construir com o Svelte, tendo visto como criar componentes, como manipular eventos e assim por diante.

E agora... vamos aprender Svelte!

4. Configurando o projeto

Como acontece com qualquer projeto JavaScript moderno, precisamos fazer tocar as músicas e dançar no ritmo: configurar o projeto! Se você quiser criar um repositório Git para o projeto, vá em frente e, em seguida, clone o repositório em sua máquina local.

Uma vez clonado, você está pronto para criar um novo projeto Svelte com degit . Não se preocupe, não é outra ferramenta para aprender! degit apenas faz cópias dos repositórios do Git e, no nosso caso, vamos clonar o modelo Svelte em uma nova pasta (ou no repositório que criamos).

Então, para recapitular, crie um novo repositório Git se você quiser e depois clone-o em sua máquina local.

Em seguida, crie um novo projeto Svelte com degit na sua nova pasta. Se a pasta não estiver vazia, degit irá te avisar e você precisará passar a opção de força:

npx degit sveltejs/template svelte-tutorial --force
Enter fullscreen mode Exit fullscreen mode

Em seguida, vá para o novo projeto e instale as dependências:

cd svelte-tutorial && npm i
Enter fullscreen mode Exit fullscreen mode

E agora você está pronto para ir!

5. Mergulhando em Svelte

Com a pasta criada, vamos dar uma olhada no que foi gerado. Abra o projeto com o seu editor de texto. Você verá vários arquivos:

  • App.svelte - o componente raiz do aplicativo
  • ‌rollup.config.js - uma configuração para o Rollup, o empacotador que o Svelte usa

Agora abra App.svelte e dê uma olhada:

<script>
    export let name;
</script>

<style>
    h1 {
        color: purple;
    }
</style>

<h1>Hello {name}!</h1>
Enter fullscreen mode Exit fullscreen mode

Isso é um componente Svelte! Mesmo. Tudo o que precisa é de uma tag de script, uma tag de estilo e um pouco de HTML. name é uma variável que é usada dentro do HTML, interpolada entre chaves. Não se preocupe muito com a declaração de exportação por enquanto. Vamos ver o que acontece depois.

6. Buscando dados com Svelte

Para começar a explorar o Svelte, começaremos imediatamente com a artilharia: vamos buscar alguns dados de uma API.

Por esse motivo, o Svelte não é tão diferente do React: ele usa um método chamado onMount. É uma função do ciclo de vida. É fácil adivinhar onde Svelte tomou emprestada a ideia: dos métodos de ciclo de vida React.

Agora vamos criar um novo componente Svelte chamado Fetch.svelte dentro da pasta src. Nosso componente importa o onMount do Svelte e faz uma solicitação de busca para uma API. onMount recebe uma função de callback e, dentro desse callback, fazemos a solicitação. Os dados são salvos em uma variável chamada data, acima de onMount:

<script>
  import { onMount } from "svelte";

  let data = [];

  onMount(async function() {
    const response = await fetch("https://academy.valentinog.com/api/link/");
    const json = await response.json();
    data = json;
  });
</script>
Enter fullscreen mode Exit fullscreen mode

Agora abra App.svelte e importe o componente recém-criado (você pode se livrar de tudo, exceto da tag de script):

<script>
  import Fetch from "./Fetch.svelte";
</script>

<Fetch />
Enter fullscreen mode Exit fullscreen mode

Como você pode ver, a sintaxe para usar componentes lembra o JSX do React. Como esse componente faz apenas uma chamada de API, mas ainda não exibe nada, vamos adicionar mais coisas à mistura.

7. Criando listas com "each"

Em React estamos acostumados com a função de mapa para criar listas de elementos. Em Svelte existe um bloco chamado "each". Vamos usá-lo para criar uma lista de links. A API retorna uma matriz de objetos e cada objeto possui um título e uma URL. Vamos adicionar um bloco "each" agora:

<script>
  import { onMount } from "svelte";

  let data = [];

  onMount(async function() {
    const response = await fetch("https://academy.valentinog.com/api/link/");
    const json = await response.json();
    data = json;
  });
</script>

{#each data as link}
// faz algo //
{/each}
Enter fullscreen mode Exit fullscreen mode

Observe como "each" produz os dados variáveis de onde eu extraio cada elemento como "link". Com o bloco no lugar agora é hora de gerar uma lista de elementos, verifique colocar um elemento ul em torno do bloco "each":

<script>
  import { onMount } from "svelte";

  let data = [];

  onMount(async function() {
    const response = await fetch("https://academy.valentinog.com/api/link/");
    const json = await response.json();
    data = json;
  });
</script>

<ul>
  {#each data as link}
    <li>
      <a href={link.url}>{link.title}</a>
    </li>
  {/each}
</ul>
Enter fullscreen mode Exit fullscreen mode

Agora, no seu terminal, entre na pasta do seu projeto e execute:

npm run dev
Enter fullscreen mode Exit fullscreen mode

Visite http://localhost:5000/ e você verá uma lista de links:

Bom trabalho! Você aprendeu como gerar listas de elementos no Svelte. Mas agora vamos tornar nosso componente mais reutilizável.

8. Passando "props"

A capacidade de reutilizar componentes na interface do usuário é a "razão principal" de bibliotecas JavaScript modernas. Em React, por exemplo, há o conceito de props, atributos personalizados (e até mesmo função ou outros componentes) que podemos passar para os nossos componentes para torná-los mais flexíveis.

No momento, o Fetch.svelte não é tão reutilizável, a URL é única. Mas não se preocupe, os componentes da Svelte também podem receber props do lado de fora. Vamos começar fazendo a url uma variável (mostrarei apenas a parte relevante do componente):

<script>
  import { onMount } from "svelte";

  let url = "https://academy.valentinog.com/api/link/";
  let data = [];

  onMount(async function() {
    const response = await fetch(url);
    const json = await response.json();
    data = json;
  });
</script>
Enter fullscreen mode Exit fullscreen mode

Certo, agora há um truque para tornar a url uma prop: basta prefixar a variável com export.

<script>
  import { onMount } from "svelte";

  // exporta a variável para transforma-la em uma prop
  export let url = "https://academy.valentinog.com/api/link/";
  let data = [];

  onMount(async function() {
    const response = await fetch(url);
    const json = await response.json();
    data = json;
  });
</script>
Enter fullscreen mode Exit fullscreen mode

Agora abra App.svelte e atualize o componente Fetch passando uma prop de url:

<script>
  import Fetch from "./Fetch.svelte";
</script>

<Fetch url="https://jsonplaceholder.typicode.com/todos" />
Enter fullscreen mode Exit fullscreen mode

Agora seu componente chama o novo endpoint ao invés da URL padrão. Outra coisa interessante é que as variáveis ​​marcadas como props podem ter um valor padrão. Em nosso exemplo, "https://academy.valentinog.com/api/link/" é o valor padrão que funciona como um substituto para quando nenhuma prop é passada.

Agora vamos ver o que acontece quando precisamos de mais uma prop.

9. Múltiplas "props" e "spreading"

Componentes Svelte podem ter múltiplas props, é claro. Vamos adicionar outro título chamado title ao nosso componente:

<script>
  import { onMount } from "svelte";

  export let url = "https://academy.valentinog.com/api/link/";
  export let title = "A list of links";
  let data = [];

  onMount(async function() {
    const response = await fetch(url);
    const json = await response.json();
    data = json;
  });
</script>

<h1>{title}</h1>
<ul>
  {#each data as link}
    <li>
      <a href={link.url}>{link.title}</a>
    </li>
  {/each}
</ul>
Enter fullscreen mode Exit fullscreen mode

E novamente do App.svelte passamos a nova prop:

<script>
  import Fetch from "./Fetch.svelte";
</script>

<Fetch
  url="https://jsonplaceholder.typicode.com/todos"
  title="A list of todos" />
Enter fullscreen mode Exit fullscreen mode

Você pode achar a abordagem acima impraticável quando as props começarem a crescer em quantidade. Felizmente há uma maneira de espalhar todas as props de uma vez. Declare as props como um objeto e espalhe-os (spread) sobre o componente:

<script>
  import Fetch from "./Fetch.svelte";
  const props = {
    url: "https://jsonplaceholder.typicode.com/todos",
    title: "A list of todos"
  };
</script>

<Fetch {...props} />
Enter fullscreen mode Exit fullscreen mode

Legal, não é? Mas ainda não estou satisfeito. Eu quero tornar o componente Fetch ainda mais reutilizável. Como?

10. Componentes filhos e "render props"

"Fetch" não é um nome ruim para um componente, mas se eu olhar para ele, ele retorna uma lista HTML. Existe uma maneira de passar essa lista para o lado de fora, como uma prop children em React? Sim, é possível! No Svelte nós nos referimos aos componentes filhos como slot.

Como primeiro passo, removerei toda a marcação de Fetch.svelte e substituí-la por um slot. Vamos remover a prop title também:

<script>
  import { onMount } from "svelte";

  export let url = "https://academy.valentinog.com/api/link/";
  let data = [];

  onMount(async function() {
    const response = await fetch(url);
    const json = await response.json();
    data = json;
  });
</script>

<slot />
Enter fullscreen mode Exit fullscreen mode

Em seguida eu posso passar elementos filhos para Fetch a partir do elemento pai, isso acontece em App.svelte:

<script>
  import Fetch from "./Fetch.svelte";
  const props = {
    url: "https://jsonplaceholder.typicode.com/todos"
  };
</script>

<Fetch {...props}>
  <h1>A list of todos</h1>
  <ul>
    <li>now what?</li>
  </ul>
</Fetch>
Enter fullscreen mode Exit fullscreen mode

Mas agora nós temos um problema. Preciso dos dados que estão dentro do Fetch.svelte pois não quero criar a lista manualmente.

Em React você teria utilizado uma HOC, render props ou hooks. Em outras palavras, quero renderizar um componente filho, mas o filho deve obter dados do componente pai.

No Svelte você pode obter o mesmo resultado passando valores de volta ao componente pai. Primeiro passe dados como uma prop para o seu slot:

<script>
  import { onMount } from "svelte";

  export let url = "https://academy.valentinog.com/api/link/";
  export let title = "A list of links";
  let data = [];

  onMount(async function() {
    const response = await fetch(url);
    const json = await response.json();
    data = json;
  });
</script>

<!-- {data} é um atalho para data={data} -->
<slot {data} />
Enter fullscreen mode Exit fullscreen mode

E do lado de fora, você pode acessar data usando a notação "let: data = {data}", aqui encurtado para "let: data":

<script>
  import Fetch from "./Fetch.svelte";
  const props = {
    url: "https://jsonplaceholder.typicode.com/todos"
  };
</script>

<!-- "let:data" é como encaminhar os dados internos de um componente um nível para cima. -->
<Fetch {...props} let:data>
  <h1>A list of todos</h1>
  <ul>
    {#each data as link}
      <li>{link.title}</li>
    {/each}
  </ul>
</Fetch>
Enter fullscreen mode Exit fullscreen mode

Agora posso usar data do componente Fetch e eles estarão disponíveis para cada bloco. É como encaminhar os dados internos de um componente um nível para cima.

Parece uma abordagem legal, embora possa ser contra-intuitivo no começo. O que você acha? Na próxima seção, veremos o tratamento de eventos no Svelte.

11. Manipulando eventos e modificadores de eventos

Vamos construir um componente de formulário para ilustrar como a Svelte lida com eventos. Crie um novo arquivo chamado Form.svelte. Por enquanto, ele conterá uma entrada para pesquisa e um botão do tipo submit:

<script>

</ script>

<form>
  <label for = "search"> Pesquisa: </ label>
  <input type = "search" id = "search" obrigatório />
  <button type = "submit"> Pesquisar </ button>
</ form>
Enter fullscreen mode Exit fullscreen mode

(Como exercício, você pode extrair todos os elementos em seu próprio componente).

Em seguida, inclua o novo componente dentro de App.svelte:

<script>
  import Form from "./Form.svelte";
</script>

<Form />
Enter fullscreen mode Exit fullscreen mode

Agora o aplicativo deve renderizar seu formulário no navegador. Nesse ponto, se você tentar enviar o formulário, o comportamento padrão será executado: o navegador irá atualizar a página.

Para assumir o controle do formulário em JavaScript "vanilla", eu registraria um ouvinte de evento para o evento submit. Então, dentro do manipulador eu evitaria o padrão com event.preventDefault():

// vanilla JS example
var form = document.getElementsByTagName('form')[0]

form.addEventListener('submit', function(event){
    event.preventDefault();
});
Enter fullscreen mode Exit fullscreen mode

As coisas são um pouco diferentes dentro de um componente Svelte: os manipuladores de eventos são registrados com "on:" seguidos respectivamente pelo nome do evento / função do manipulador:

<script>
  function handleSubmit(event) {
    // faz algo
  }
</script>

<form on:submit={handleSubmit}>
  <label for="search">Search:</label>
  <input type="search" id="search" required />
  <button type="submit">Search</button>
</form>
Enter fullscreen mode Exit fullscreen mode

Além disso, no Svelte existem modificadores de eventos. Os mais importantes são:

  • preventDefault
  • stopPropagation
  • once

Para interromper o efeito padrão em nosso formulário, podemos usar o modificador preventDefault, após o nome do evento:

<script>
  function handleSubmit(event) {
    // faz algo
  }
</script>

<form on:submit|preventDefault={handleSubmit}>
  <label for="search">Search:</label>
  <input type="search" id="search" required />
  <button type="submit">Search</button>
</form>
Enter fullscreen mode Exit fullscreen mode

Você também pode passar o handleSubmit como um suporte para tornar o componente mais flexível. Aqui está um exemplo, com um prop padrão:

<script>
  export let handleSubmit = function(event) {
    // faz algo
  };
</script>

<form on:submit|preventDefault={handleSubmit}>
  <label for="search">Search:</label>
  <input type="search" id="search" required />
  <button type="submit">Search</button>
</form>
Enter fullscreen mode Exit fullscreen mode

É isso aí. Agora vamos levar este simples aplicativo um passo adiante: Eu quero filtrar a lista de links. O formulário já está em vigor, mas precisamos conectar Fetch.svelte com Form.svelte. Vamos fazer isso!

12. Uma rápida recapitulação

Vamos recapitular o que fizemos até agora. Nós temos dois componentes, Fetch.svelte:

<script>
  import { onMount } from "svelte";

  export let url = "https://academy.valentinog.com/api/link/";

  let data = [];

  onMount(async function() {
    const response = await fetch(url);
    const json = await response.json();
    data = json;
  });
</script>

<slot {data} />
Enter fullscreen mode Exit fullscreen mode

e Form.svelte:

<script>
  export let handleSubmit = function(event) {
    // valor padrão da prop
  };
</script>

<form on:submit|preventDefault={handleSubmit}>
  <label for="search">Search:</label>
  <input type="search" id="search" required />
  <button type="submit">Search</button>
</form>
Enter fullscreen mode Exit fullscreen mode

Em seguida, há App.svelte, que é o componente raiz. Por conveniência, vamos renderizar o formulário e buscar dentro do aplicativo:

<script>
  import Fetch from "./Fetch.svelte";
  import Form from "./Form.svelte";
</script>

<Form />
<Fetch let:data>
  <h1>A list of links</h1>
  <ul>
    {#each data as link}
      <li>
        <a href={link.url}>{link.title}</a>
      </li>
    {/each}
  </ul>
</Fetch>
Enter fullscreen mode Exit fullscreen mode

Fetch.svelte pega os dados de uma API e envia os dados um nível á cima. Então, ao usar cada bloco como um slot, posso passar dados para seus filhos.

Agora quero que o usuário filtre os dados, dependendo do termo de pesquisa que ela insere no formulário. Parece que Form e Fetch precisam se comunicar. Vamos ver como podemos implementar isso.

13. Implementando o recurso de pesquisa

A maneira como vejo esse recurso é que precisamos de um termo de pesquisa para filtrar o array de dados. O termo de pesquisa pode ser uma prop passada para Fetch.svelte a partir do componente pai. Abra o Fetch.svelte e adicione a nova prop searchTerm:

<script>
  import { onMount } from "svelte";

  export let url = "https://academy.valentinog.com/api/link/";

  // nova prop
  export let searchTerm = undefined;

  let data = [];

  onMount(async function() {
    const response = await fetch(url);
    const json = await response.json();
    data = json;
  });
</script>

<slot {data} />
Enter fullscreen mode Exit fullscreen mode

(searchTerm é atribuído undefined para evitar que Svelte alerte no console "Fetch foi criado sem a prop searchTerm esperada").

Em seguida, precisamos de uma nova variável para manter a resposta em json, pois filtraremos essa resposta dependendo do searchTerm. Adicione uma nova variável chamada jsonResponse e, ao invés de salvar no json, use jsonResponse para armazenar a resposta da API:

<script>
  import { onMount } from "svelte";

  export let url = "https://academy.valentinog.com/api/link/";

  // nova prop
  export let searchTerm;

  // nova variável
  let jsonResponse = [];

  let data = [];

  onMount(async function() {
    const response = await fetch(url);
    const json = await response.json();

    // salva a resposta na nova variável
    jsonResponse = json;
  });
</script>

<slot {data} />
Enter fullscreen mode Exit fullscreen mode

Neste ponto, data terá:

  • o jsonResponse original se nenhum searchTerm for fornecido
  • um array filtrado se o searchTerm não estiver vazio

Para filtrar o elemento do array, podemos utilizar .match com a propriedade title baseada em um RegExp. (A API retorna um array de objetos. Cada objeto tem title e url). Uma primeira implementação poderia ser:

const regex = new RegExp(searchTerm, "gi");

const data = searchTerm
    ? jsonResponse.filter(element => element.title.match(regex))
    : jsonResponse;
Enter fullscreen mode Exit fullscreen mode

Faz sentido! Vamos ver o componente completo:

<script>
  import { onMount } from "svelte";

  export let url = "https://academy.valentinog.com/api/link/";

  // nova prop
  export let searchTerm = undefined;

  // nova variável
  let jsonResponse = [];

  const regex = new RegExp(searchTerm, "gi");

  const data = searchTerm
    ? jsonResponse.filter(element => element.title.match(regex))
    : jsonResponse;

  onMount(async function() {
    const response = await fetch(url);
    const json = await response.json();

    // salva a resposta na nova variável
    jsonResponse = json;
  });
</script>

<slot {data} />
Enter fullscreen mode Exit fullscreen mode

Neste ponto, precisamos de alguns ajustes no App.svelte. searchTerm deve ser uma prop dinâmica sendo enviada pelo componente pai. Em seguida, interceptamos o valor da entrada quando um usuário envia o formulário. Abra o App.svelte e passe o searchTerm como prop para Fetch:

<script>
  import Fetch from "./Fetch.svelte";
  import Form from "./Form.svelte";

  let searchTerm;
</script>

<Form />
<Fetch {searchTerm} let:data>
  <h1>A list of links</h1>
  <ul>
    {#each data as link}
      <li>
        <a href={link.url}>{link.title}</a>
      </li>
    {/each}
  </ul>
</Fetch>
Enter fullscreen mode Exit fullscreen mode

Em seguida, criamos e passamos o handleSubmit como prop para o Form e, dentro do App.svelte, salvamos o termo de pesquisa inserido pelo usuário dentro da variável searchTerm:

<script>
  import Fetch from "./Fetch.svelte";
  import Form from "./Form.svelte";

  let searchTerm;

  function handleSubmit() {
    const { value } = this.elements.search;
    searchTerm = value;
  }
</script>

<Form {handleSubmit} />
<Fetch {searchTerm} let:data>
  <h1>A list of links</h1>
  <ul>
    {#each data as link}
      <li>
        <a href={link.url}>{link.title}</a>
      </li>
    {/each}
  </ul>
</Fetch>
Enter fullscreen mode Exit fullscreen mode

Quase pronto. Salve todos os arquivos e execute o servidor de desenvolvimento. Você vai ver... uma página em branco!

O que está acontecendo? Segure firme e vá para a próxima seção!

14. Reatividade

A maneira como a Svelte lida com valores calculados pode não parecer intuitiva no começo. Nosso problema está em Fetch.svelte e vem das seguintes linhas:

const regex = new RegExp(searchTerm, "gi");

const data = searchTerm
    ? jsonResponse.filter(element => element.title.match(regex))
    : jsonResponse;
Enter fullscreen mode Exit fullscreen mode

Se você pensar sobre isso, temos dois valores calculados. RegExp depende do searchTerm e queremos recalcular o primeiro toda vez que o último for alterado.

Então nós temos a variável data: ele deve recalcular também toda vez que searchTerm e RegExp mudarem. É como uma planilha: os valores podem depender de outros valores.

Svelte se inspira em "programação reativa" e usa uma sintaxe estranha para os chamados valores computados. Esses valores são chamados de "declarações reativas" no Svelte 3. Veja como você deve ajustar o código acima:

$: regex = new RegExp(searchTerm, "gi");

$: data = searchTerm
    ? jsonResponse.filter(element => element.title.match(regex))
    : jsonResponse;
Enter fullscreen mode Exit fullscreen mode

$: não é uma língua alienígena. É simplesmente JavaScript, e é chamado de Instrução Rotulada.

Aqui está o Fetch.svelte completo novamente:

<script>
  import { onMount } from "svelte";

  export let url = "https://academy.valentinog.com/api/link/";
  export let searchTerm = undefined;
  let jsonResponse = [];

  $: regex = new RegExp(searchTerm, "gi");

  $: data = searchTerm
    ? jsonResponse.filter(element => element.title.match(regex))
    : jsonResponse;

  onMount(async function() {
    const response = await fetch(url);
    const json = await response.json();
    jsonResponse = json;
  });
</script>

<slot {data} />
Enter fullscreen mode Exit fullscreen mode

Agora, o recurso de pesquisa funcionará como esperado:

(Filtragem de Links no nível da API teriam sido uma abordagem melhor do que buscar todos os links todas as vezes).

Agora confira a próxima seção se você está curioso para ver como o mesmo "aplicativo" é implementado com o React.

15. Comparando com React

Como que o mesmo aplicativo ficaria em React? Aqui está o App.js, que é o equivalente do App.svelte:

import React, { useState } from "react";
import Fetch from "./Fetch";
import Form from "./Form";

function App() {
  const [searchTerm, setSearchTerm] = useState("");

  const fetchProps = {
    url: "https://academy.valentinog.com/api/link/",
    searchTerm
  };

  function handleSubmit(event) {
    event.preventDefault();
    const { value } = event.target.elements.search;
    setSearchTerm(value);
  }

  return (
    <>
      <Form handleSubmit={handleSubmit} />
      <Fetch
        {...fetchProps}
        render={links => {
          return (
            <>
              <h1>A list of links</h1>
              <ul>
                {links.map(link => (
                  <li key={link.url}>
                    <a href={link.url}>{link.title}</a>
                  </li>
                ))}
              </ul>
            </>
          );
        }}
      />
    </>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Aqui estou usando o componente Fetch com uma prop de renderização. Eu poderia usar um hook, mas eu queria mostrar a você como o mesmo conceito se aplica tanto ao Svelte quanto ao React.

Em outras palavras:

  • Para acessar o estado de um componente pai a partir de um componente filho no React, você pode usar props de renderização (ou um hook personalizado para compartilhamento da busca de dados)
  • para acessar o estado de um componente pai de um slot Svelte, você pode encaminhar os dados para cima a partir do pai

Se você comparar App.js com a versão Svelte (clique aqui), poderá ver que um típico componente Svelte é menos detalhado que um equivalente em React.

Facilmente explicado pelo fato de que no Svelte 3 não há necessidade de chamar explicitamente setSomeState ou funções similares. O Svelte "reage" apenas atribuindo valores às variáveis.

Em seguida, Form.js, um espelho React do Form.svelte:

import React from "react";

function Form(props) {
  return (
    <form onSubmit={props.handleSubmit}>
      <label htmlFor="search">Search:</label>
      <input type="search" id="search" required={true} />
      <button type="submit">Search</button>
    </form>
  );
}

export default Form;
Enter fullscreen mode Exit fullscreen mode

Nada muito diferente, apenas uma função recebendo algumas props.

Finalmente, há o Fetch.js, espelhando o Fetch.svelte:

import { useState, useEffect } from "react";

function Fetch(props) {
  const { url, searchTerm } = props;
  const [links, setLinks] = useState([]);
  const regex = new RegExp(searchTerm, "gi");
  const data = searchTerm
    ? links.filter(link => link.title.match(regex))
    : links;

  useEffect(() => {
    fetch(url)
      .then(response => response.json())
      .then(json => setLinks(json));
  }, [url]);

  return props.render(data);
}

Fetch.defaultProps = {
  url: "https://academy.valentinog.com/api/link/"
};

export default Fetch;
Enter fullscreen mode Exit fullscreen mode

O componente acima usa hooks e render props: novamente, isso é desnecessário porque você pode extrair tudo em um hook personalizado. E aqui está Fetch.svelte:

<script>
  import { onMount } from "svelte";

  export let url = "fillThis";
  export let searchTerm = undefined;
  let jsonResponse = [];

  $: regex = new RegExp(searchTerm, "gi");

  $: data = searchTerm
    ? jsonResponse.filter(element => element.title.match(regex))
    : jsonResponse;

  onMount(async function() {
    const response = await fetch(url);
    const json = await response.json();
    jsonResponse = json;
  });
</script>

<slot {data} />
Enter fullscreen mode Exit fullscreen mode

Para mim, eles são muito parecidos! No entanto, esses exemplos não estão nem perto de um aplicativo grande e sua milhagem pode variar.

16. Como o Svelte se compara ao React e Vue?

Já me perguntaram o que acho de Svelte comparado a React e Vue. Eu não posso falar por Vue porque eu não tenho muita experiência com isso, mas eu posso ver como Svelte toma algumas coisas emprestado.

Falando de React, Svelte raciocina bem para mim e parece mais intuitivo do que o seu equivalente. Num piscar de olhos, o Svelte 3 parece apenas mais uma maneira de fazer as coisas, talvez mais esperto do que o React. Mas a base dele é sólida.

O que é realmente interessante em Svelte é que não há DOM Virtual, diferente de React e Vue. Em outras palavras, não há abstração entre a biblioteca e o Modelo de Objeto de Documento real: o Svelte 3 compila o JavaScript "vanilla" mínimo possível. Isso é útil se você estiver executando seu aplicativo em ambientes restritos.

Para recapitular, o Svelte é uma biblioteca bastante interessante, mas darei mais tempo, pelo menos, até que a documentação, o ecossistema e as ferramentas fiquem maduras.

17. Mais Recursos

Para aprender mais sobre o Svelte, não posso recomendar o suficiente a documentação oficial e os exemplos.

O código fonte deste tutorial está disponível aqui.

Também recomendo assistir a essa apresentação do criador do Svelte:

https://www.youtube.com/watch?v=AdNJ3fydeao

18. Finalizando

Para onde ir a partir daqui? Há muito mais para aprender sobre o Svelte 3 se você quiser. E há muitas novidades prontas para uso:

  • Estilos com escopo (scoped styles)
  • data-binding de duas vias (two way data-binding)
  • Gestão de estados (state management)
  • Animações incorporadas (built-in animations)

E antes de dizer adeus, algumas palavras finais:

JavaScript é brutal. Bibliotecas vêm e vão e há sempre algo novo para aprender. Ao longo dos anos, aprendi a não ficar muito amarrado a nenhuma biblioteca JavaScript em particular, mas com toda a honestidade, eu realmente gosto de React e Redux.

React trouxe "componentes" para as massas, por outro lado, a própria biblioteca requer alta especialização para ser dominada. Vue, ao contrário, é mais amigável para iniciantes, mas infelizmente não é percebido como “moderno” como React (o que quer que isso signifique).

O Svelte 3 tem o melhor dos dois mundos: os componentes Svelte se parecem com os do Vue e alguns dos conceitos do React se aplicam também.

O Svelte é mais intuitivo que o React , especialmente se pensarmos em um iniciante que se aproxima do React na era do Hooks. Porém, React não está indo embora tão cedo, mas estou ansioso para ver onde Svelte está indo.

E para você, meu amigo, sempre há meu antigo conselho: sempre continue aprendendo a plataforma web e você será capaz de dominar qualquer biblioteca JavaScript que vier em seguida.

Obrigado por ler e fique ligado neste blog!

Créditos ⭐️

💖 💪 🙅 🚩
oieduardorabelo
Eduardo Rabelo

Posted on July 21, 2019

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related