Cómo hacer búsquedas de usuarios en GitHub sin React + RxJS 6 + Recompose

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 responsabilidad
Puede 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 interactiva

Escribe 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!

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


All Articles