Como fazer pesquisas de usuários no GitHub sem React + RxJS 6 + Recompose

Este artigo é uma resposta ao artigo de tradução “Como pesquisar usuários no GitHub usando o React + RxJS 6 + Recompose” , que ontem nos ensinou como usar o React, o RxJS e o Recompose juntos. Bem, proponho agora ver como isso pode ser implementado sem essas ferramentas.




Isenção de responsabilidade
Pode parecer para muitos que este artigo contém elementos de trolling, foi escrito às pressas e em um fã ... Então é isso.


Como este é um artigo de retorno, decidi compilá-lo no mesmo formato passo a passo que o original. Além disso, o artigo também tem como objetivo comparar a implementação original com a descrita aqui. Portanto, contém uma abundância de referências e citações do original. Vamos começar.

Este artigo é para pessoas com experiência com React e RxJS. Estou apenas compartilhando modelos que achei úteis para criar uma interface do usuário.

Este artigo é para pessoas com experiência em Javascript (ES6), HTML e CSS. Além disso, em minha implementação, usarei a estrutura SvelteJS “desaparecendo” , mas é tão simples que você não precisa ter experiência em usá-la para entender o código.

Estamos fazendo a mesma coisa:



Sem classes, trabalhando com um ciclo de vida ou setState.

Sim, sem classes, trabalhando com um ciclo de vida ou setState. E também sem React, ReactDOM, RxJS, Recompose. Além disso, sem componentFromStream, createEventHandler, combineLatest, map, startWith, setObservableConfig, BehaviorSubject, merge, of, catchError, delay, filter, map, arranque, switchMap, toque em {outra besteira} ... Em resumo, você entende.

Preparação


Tudo o que você precisa está no meu exemplo do REPL no site do SvelteJS. Você pode cheirar lá, localmente, baixando a fonte de lá (botão com um ícone de característica).

Primeiro, crie um arquivo simples App.html, que será o componente raiz do nosso widget, com o seguinte conteúdo:

<input placeholder="GitHub username"> <style> input { font-size: 20px; border: 1px solid black; border-radius: 3px; margin-bottom: 10px; padding: 10px; } </style> 


A seguir, uso os estilos do artigo original. No momento, eles estão no escopo, ou seja, se aplicam apenas a este componente e você pode usar com segurança os nomes das tags, quando relevante.

Escreverei estilos diretamente nos componentes, porque o SFC e também porque o REPL não suporta a exportação de CSS / JS / HTML para arquivos diferentes, embora isso seja feito facilmente com os pré-processadores Svelte .

Recompor


Descansando ...

Componente em linha


... banhos de sol ...

Configuração


... tomando café ...

Recompor + RxJS


... enquanto outros ...

Mapa


... trabalho.

Adicionar um manipulador de eventos


Não é realmente um manipulador, é claro, apenas uma ligação:

 <input bind:value=username placeholder="GitHub username"> 


Bem, definimos o valor padrão do nome de usuário:

 <script> export default { data() { return { username: '' }; } }; </script> 


Agora, se você começar a digitar algo no campo de entrada, o valor do nome de usuário será alterado.


Problema com ovo e galinha


Sem galinhas, sem ovos, sem problemas com outros animais, não usamos RxJS.

Tricotar juntos


Tudo já está reativo e conectado. Então, tomamos café.

Componente do usuário


Este componente será responsável por exibir o usuário cujo nome iremos transferir para ele. Ele receberá valor do componente App e o converte em uma solicitação AJAX.

“Uau uau uau, vá com calma” ©

Conosco, este componente será estúpido e apenas exibirá um belo cartão de usuário de acordo com um modelo conhecido anteriormente. Não importa de onde os dados possam vir e / ou em que local da interface queremos mostrar este cartão.

O componente User.html será parecido com este:

 <div class="github-card user-card"> <div class="header User" /> <a class="avatar" href="https://github.com/{login}"> <img src="{avatar_url}&s=80" alt={name}> </a> <div class="content"> <h1>{name || login}</h1> <ul class="status"> <li> <a href="https://github.com/{login}?tab=repositories"> <strong>{public_repos}</strong>Repos </a> </li> <li> <a href="https://gist.github.com/{login}"> <strong>{public_gists}</strong>Gists </a> </li> <li> <a href="https://github.com/{login}/followers"> <strong>{followers}</strong>Followers </a> </li> </ul> </div> </div> <style> /*  */ </style> 


Jsx / css


CSS foi adicionado apenas ao componente. Em vez de JSX, temos HTMLx incorporado no Svelte.

Container


O contêiner é qualquer componente pai para o componente Usuário. Nesse caso, é um componente do aplicativo.

debounceTime


A depuração da entrada de texto não faz sentido se a operação substituir apenas o valor no modelo de dados. Portanto, na própria ligação, não precisamos disso.

arrancar


filtrar


mapa


Conectar


Vamos voltar ao App.html e importar o componente Usuário:

 import User from './User.html'; 


Pedido de dados


O GitHub fornece uma API para recuperar informações do usuário:

Para demonstração, basta escrever um pequeno arquivo api.js. que abstrairá o recebimento de dados e exportará a função correspondente:

 import axios from 'axios'; export function getUserCard(username) { return axios.get(`https://api.github.com/users/${username}`) .then(res => res.data); } 


E assim, importamos essa função para App.html.

Agora, formulamos o problema em um idioma mais específico: precisamos alterar outro valor ao alterar um valor no modelo de dados (nome de usuário). Nós o chamaremos de usuário, respectivamente - dados do usuário que obtemos da API. Reatividade em toda a sua glória.

Para fazer isso, escreva uma propriedade Svelte calculada usando a seguinte construção em App.html:

 <script> import { getUserCard } from './api.js'; ... export default { ... computed: { user: ({ username }) => username && getUserCard(username) } }; </script> 


É isso, agora, quando você altera o nome de usuário, uma solicitação será enviada para receber dados sobre esse valor. No entanto, como os binders respondem a todas as alterações, ou seja, inserem um campo de texto, haverá muitas solicitações e excederemos rapidamente todos os limites disponíveis.

No artigo original, esse problema é resolvido pela função debounceTime incorporada ao RxJS, o que nos impede de solicitar dados com muita frequência. Para nossa implementação, você pode usar a solução autônoma, como debounce-promessa ou qualquer outra solução adequada, pois há muito por onde escolher.

 <script> import debounce from 'debounce-promise'; import { getUserCard } from './api.js'; ... const getUser = debounce(getUserCard, 1000); ... export default { ... computed: { user: ({ username }) => username && getUser(username) } }; </script> 


Portanto, essa lib cria uma versão de rejeição da função passada para ela, que usamos na propriedade computada.

switchMap


ajax


O RxJS fornece sua própria implementação de ajax que funciona muito bem com o switchMap!

Como não usamos RxJS e, especialmente, switchMap, podemos usar qualquer biblioteca para trabalhar com ajax.

Uso axios porque é conveniente para mim, mas você pode usar qualquer coisa e isso não muda a essência do assunto.

Experimente


Primeiro, precisamos registrar o componente Usuário para usá-lo como uma tag de modelo, pois a importação em si não adiciona o componente ao contexto do modelo:

 <script> import User from './User.html'; ... export default { components: { User } ... }; </script> 

Apesar do rabisco aparentemente excessivo, isso permite, entre outras coisas, atribuir nomes de tags diferentes a instâncias do mesmo componente, tornando seus modelos mais semanticamente compreensíveis.

Além disso, o valor do usuário não são os dados em si, mas uma promessa para esses dados. Como somos freelancers e não queremos fazer nenhum trabalho, basta tomar café com biscoitos.

Para transferir dados reais para o componente Usuário, podemos usar um design especial para trabalhar com promessas:

 {#await user} <!--     --> {:then user} <!--      .    . --> {#if user} <User {...user} /> {/if} {/await} 

Faz sentido verificar a existência do objeto de dados antes de passá-lo para o componente Usuário. O operador Spread aqui permite que você “divida” um objeto em objetos separados ao criar uma instância do componente Usuário.



Trabalho mais curto.

Tratamento de erros


Tente digitar um nome de usuário inexistente.
...
Nosso aplicativo está quebrado.

Seu provavelmente sim, mas o nosso definitivamente não é))) Simplesmente nada acontecerá, embora esse certamente não seja o caso.

catchError


Adicione um bloco adicional ao processamento de promessa rejeitada:

 {#await user} {:then user} {#if user} <User {...user} /> {/if} {:catch error} <Error {...error} /> {/await} 


Erro de componente


 <div class="error"> <h2>Oops!</h2> <b>{response.status}: {response.data.message}</b> <p>Please try searching again.</p> </div> 

Agora nossa interface do usuário parece muito melhor:

E não diga, e mais importante ainda, nenhum esforço.



Indicador de carregamento


Em suma, uma nova heresia começou por aí, com todos os tipos de assuntos comportamentais e outros como eles. Apenas adicionamos um indicador de carregamento e não ordenharemos o elefante:

 {#await user} <h3>Loading...</h3> {:then user} {#if user} <User {...user} /> {/if} {:catch error} <Error {...error} /> {/await} 

Resultado?

Dois pequenos componentes sem lógica (Usuário e Erro) e um componente de controle (App), onde a lógica de negócios mais complexa é descrita em uma linha - criando uma propriedade calculada. Não escovar objetos observáveis ​​da cabeça aos pés e conectar +100500 ferramentas que você não precisa.

Demonstração interativa

Escreva um código simples e claro. Escreva menos código, o que significa menos trabalho e mais tempo com sua família. Live!

Toda felicidade e saúde!

All :)


Fyi


Se você já olhou o exemplo no REPL, provavelmente notou a torrada com um aviso no canto inferior esquerdo:
Compilado, mas com 1 aviso - verifique o console para obter detalhes

Se você não estiver com preguiça de abrir o console, você verá esta mensagem:
Seletor CSS não utilizado
.user-card .Organization {
posição de fundo: canto superior direito;
}

O Svelte Static Analyzer nos informa que alguns estilos de componentes não são usados. Além disso, a seu pedido ou o comando das configurações padrão do compilador, os estilos não utilizados serão removidos do pacote css final sem a sua participação.

P / s


Leia outros artigos sobre o Svelte e também procure o canal de telegrama em russo SvelteJS . Teremos o maior prazer em vê-lo!

Source: https://habr.com/ru/post/pt419653/


All Articles