Este artículo es una respuesta al artículo de traducción
"Cómo buscar usuarios en GitHub usando React + RxJS 6 + Recompose" , que ayer nos enseñó cómo usar React, RxJS y Recompose juntos. Bueno, ahora propongo ver cómo se puede implementar esto sin estas herramientas.

Descargo de responsabilidadPuede parecer a muchos que este artículo contiene elementos de trolling, fue escrito a toda prisa y en un ventilador ... Entonces, esto es así.
Como se trata de un artículo de devolución, decidí construirlo en el mismo formato paso a paso que el original. Además, el artículo también tiene como objetivo comparar la implementación original con la que se describe aquí. Por lo tanto, contiene una gran cantidad de referencias y citas del original. Empecemos
Este artículo es para personas con experiencia con React y RxJS. Solo estoy compartiendo plantillas que encontré útiles para crear una interfaz de usuario de este tipo.
Este artículo es para personas con experiencia en Javascript (ES6), HTML y CSS. Además, en mi implementación utilizaré el
marco SvelteJS "desapareciente" , pero es tan simple que no necesita tener experiencia en usarlo para comprender el código.
Estamos haciendo lo mismo:

Sin clases, trabajando con un ciclo de vida o setState.
Sí, sin clases, trabajando con un ciclo de vida o setState. Y también sin React, ReactDOM, RxJS, Recompose. Y además, sin componentFromStream, createEventHandler, combineLatest, map, startWith, setObservableConfig, BehaviorSubject, merge, of, catchError, delay, filter, map, pluck, switchMap, tap, {otro bullshit} ... En resumen, lo entiendes.
Preparación
Todo lo que necesitas está en mi
ejemplo REPL en el sitio web de SvelteJS. Puede oler allí, ya sea localmente, descargando la fuente desde allí (botón con un icono característico).
Primero, cree un archivo simple App.html, que será el componente raíz de nuestro widget, con los siguientes contenidos:
<input placeholder="GitHub username"> <style> input { font-size: 20px; border: 1px solid black; border-radius: 3px; margin-bottom: 10px; padding: 10px; } </style>
De aquí en adelante, uso los estilos del artículo original. Tenga en cuenta que en este momento están dentro del alcance, es decir se aplica solo a este componente y puede usar de forma segura los nombres de las etiquetas cuando sea relevante.
Escribiré estilos directamente en los componentes, porque SFC, y también porque REPL no admite poner CSS / JS / HTML en diferentes archivos, aunque esto se hace fácilmente usando
preprocesadores Svelte .
Recomponer
Descansando ...
Componente en línea
... tomando el sol ...
Configuracion
... tomando café ...
Recomponer + RxJS
... mientras que otros ...
Mapa
... trabajo
Agregar un controlador de eventos
No es realmente un controlador, por supuesto, solo un enlace:
<input bind:value=username placeholder="GitHub username">
Bueno, definimos el valor de nombre de usuario predeterminado:
<script> export default { data() { return { username: '' }; } }; </script>
Ahora, si comienza a escribir algo en el campo de entrada, el valor del nombre de usuario cambiará.

Problema de huevo y pollo
Sin gallinas, sin huevos, sin problemas con otros animales, no utilizamos RxJS.
Tejer juntos
Todo ya es reactivo y conectado. Entonces tomamos café.
Componente de usuario
Este componente será responsable de mostrar al usuario cuyo nombre le transferiremos. Recibirá valor del componente de la aplicación y lo traducirá en una solicitud AJAX.
"Wow wow wow, tómalo con calma" ©
Con nosotros, este componente será estúpido y solo mostrará una hermosa tarjeta de usuario de acuerdo con un modelo previamente conocido. No importa de dónde pueden venir los datos y / o en qué lugar de la interfaz queremos mostrar esta tarjeta.
El componente User.html se verá así:
<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
Se acaba de agregar CSS al componente. En lugar de JSX, tenemos
HTMLx incrustado en Svelte.
Contenedor
El contenedor es cualquier componente principal para el componente Usuario. En este caso, es un componente de la aplicación.
debounceTime
La depuración de entrada de texto no tiene sentido si la operación solo sobrescribe el valor en el modelo de datos. Entonces, en el enlace en sí, no necesitamos esto.
arrancar
filtro
mapa
Conectar
Volvamos a App.html e importemos el componente Usuario:
import User from './User.html';
Solicitud de datos
GitHub proporciona una API para recuperar información del usuario:
Para la demostración, simplemente escribimos un pequeño archivo api.js que abstraerá la recepción de datos y exportará la función correspondiente:
import axios from 'axios'; export function getUserCard(username) { return axios.get(`https://api.github.com/users/${username}`) .then(res => res.data); }
Y así, importamos esta función en App.html.
Ahora formulamos el problema en un lenguaje más específico: necesitamos cambiar otro valor al cambiar un valor en el modelo de datos (nombre de usuario). Lo llamaremos usuario, respectivamente, datos de usuario que obtenemos de la API. Reactividad en todo su esplendor.
Para hacer esto, escriba una propiedad Svelte calculada utilizando la siguiente construcción en App.html:
<script> import { getUserCard } from './api.js'; ... export default { ... computed: { user: ({ username }) => username && getUserCard(username) } }; </script>
Eso es todo, ahora cuando cambie el nombre de usuario, se enviará una solicitud para recibir datos sobre este valor. Sin embargo, dado que las carpetas responden a cada cambio, es decir, la entrada en un campo de texto, habrá demasiadas solicitudes y superaremos rápidamente todos los límites disponibles.
En el artículo original, este problema se resuelve con la función debounceTime integrada en RxJS, que nos impide solicitar datos con demasiada frecuencia. Para nuestra implementación, puede usar la solución independiente, como
debounce-promise o cualquier otra solución adecuada, ya que hay mucho para elegir.
<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>
Entonces, esta biblioteca crea una versión antirrebote de la función que se le pasa, que luego usamos en la propiedad calculada.
switchMap
ajax
¡RxJS proporciona su propia implementación ajax que funciona muy bien con switchMap!
Como no usamos RxJS y especialmente switchMap, podemos usar cualquier biblioteca para trabajar con ajax.
Uso
axios porque es conveniente para mí, pero puedes usar cualquier cosa y eso no cambia la esencia del asunto.
Prueba
Primero, debemos registrar el componente Usuario para usarlo como una etiqueta de plantilla, ya que la importación en sí no agrega el componente al contexto de la plantilla:
<script> import User from './User.html'; ... export default { components: { User } ... }; </script>
A pesar del garabato aparentemente excesivo, esto permite, entre otras cosas, dar diferentes nombres de etiquetas a instancias del mismo componente, haciendo que sus plantillas sean semánticamente más comprensibles.
Además, el valor del usuario no son los datos en sí, sino una promesa para esos datos. Debido a que somos libres y no queremos hacer ningún trabajo, solo tomemos café con galletas.
Para transferir datos reales al componente Usuario, podemos usar un diseño especial para trabajar con promesas:
{#await user} {:then user} {#if user} <User {...user} /> {/if} {/await}
Tiene sentido verificar la existencia del objeto de datos antes de pasarlo al componente Usuario. El operador Spread aquí le permite "dividir" un objeto en accesorios separados al crear una instancia del componente Usuario.

Trabajo más corto
Manejo de errores
Intenta ingresar un nombre de usuario inexistente.
...
Nuestra aplicación está rota.
El suyo probablemente sí, pero el nuestro definitivamente no))) Simplemente no sucederá nada, aunque ciertamente este no es el caso.
catchError
Agregue un bloque adicional para el procesamiento de promesa rechazada:
{#await user} {:then user} {#if user} <User {...user} /> {/if} {:catch error} <Error {...error} /> {/await}
Error de componente
<div class="error"> <h2>Oops!</h2> <b>{response.status}: {response.data.message}</b> <p>Please try searching again.</p> </div>
Ahora nuestra interfaz de usuario se ve mucho mejor:
Y no lo digas, y lo más importante, ningún esfuerzo.

Indicador de carga
En resumen, la herejía comenzó allí, con todo tipo de Sujetos de Comportamiento y otros como ellos. Solo agregamos un indicador de carga y no vamos a ordeñar al elefante:
{#await user} <h3>Loading...</h3> {:then user} {#if user} <User {...user} /> {/if} {:catch error} <Error {...error} /> {/await}
Resultado?
Dos pequeños componentes sin lógica (Usuario y Error) y un componente de control (Aplicación), donde la lógica empresarial más compleja se describe en una línea: crear una propiedad calculada. No cepille objetos observables de pies a cabeza y conecte +100500 herramientas que no necesita.
→
Demo interactivaEscribe código simple y claro. Escriba menos código, lo que significa menos trabajo y más tiempo con su familia. Vivir!
¡Toda felicidad y salud!
Todos :)
Fyi
Si ya miró el ejemplo en REPL, entonces probablemente notó el brindis con una advertencia desde la parte inferior izquierda:
Compilado, pero con 1 advertencia: consulte la consola para obtener más información
Si no eres demasiado vago para abrir la consola, verás este mensaje:
Selector CSS no utilizado
.user-card .Organization {
posición de fondo: arriba a la derecha;
}
Svelte Static Analyzer nos informa que algunos estilos de componentes no se utilizan. Además, a petición suya o el comando de la configuración predeterminada del compilador, los estilos no utilizados se eliminarán del paquete css final sin su participación.
P / s
Lea
otros artículos sobre Svelte , y mire el canal de telegramas en ruso
SvelteJS . Estaremos encantados de verte!