En este tutorial, crearemos una interfaz de usuario utilizando la API de búsqueda pública de Wikipedia junto con algunos JavaScript + RamdaJS.
Empezando
Aquí está el enlace de GitHub y el enlace Codesandbox. Abra su terminal y elija un directorio para clonarlo.
git clone [//github.com/yazeedb/ramda-wikipedia-search](//github.com/yazeedb/ramda-wikipedia-search) cd ramda-wikipedia-search yarn install (or npm install)
La master
rama tiene el proyecto terminado, así que consulte la start
rama si desea codificar.
git checkout start
¡Y empieza el proyecto!
npm start
Su navegador debería abrir automáticamente localhost: 1234.
Obtener el valor de entrada
Aquí está la aplicación inicial.
Para capturar la entrada del usuario mientras escribe, nuestro input
elemento necesita un detector de eventos.
Su src/index.js
archivo ya está conectado y listo para funcionar. Notarás que importamos Bootstrap para diseñar.
Agreguemos un detector de eventos ficticio para que todo funcione.
import 'bootstrap/dist/css/bootstrap.min.css'; const inputElement = document.querySelector('input'); inputElement.addEventListener('keyup', (event) => { console.log('value:', event.target.value); });
Sabemos que event.target.value
es la forma estándar de acceder al valor de una entrada. Ahora muestra el valor.
¿Cómo puede ayudarnos Ramda a lograr lo siguiente?
- Agarrar
event.target.value
- Recorte la salida (elimine los espacios en blanco iniciales / finales)
- Por defecto a cadena vacía si
undefined
La pathOr
función puede manejar el primer y tercer punto. Toma tres parámetros: el predeterminado, la ruta y los datos.
Entonces lo siguiente funciona perfectamente
import { pathOr } from 'ramda'; const getInputValue = pathOr('', ['target', 'value']);
Si event.target.value
es así undefined
, ¡recuperaremos una cadena vacía!
Ramda también tiene una trim
función, por lo que resuelve nuestro problema de espacios en blanco.
import { pathOr, trim } from 'ramda'; const getInputValue = (event) => trim(pathOr('', ['target', 'value'], event));
En lugar de anidar esas funciones, usemos pipe
. Vea mi artículo sobre tuberías si es nuevo para usted.
import { pathOr, pipe, trim } from 'ramda'; const getInputValue = pipe( pathOr('', ['target', 'value']), trim );
Ahora tenemos una función compuesta que toma un event
objeto, lo toma, lo toma por target.value
defecto ''
y lo recorta.
Hermoso.
Recomiendo almacenar esto en un archivo separado. Tal vez lo llame getInputValue.js
y use la sintaxis de exportación predeterminada.
Obtener la URL de Wikipedia
En el momento de escribir estas líneas, la URL de búsqueda de la API de Wikipedia es //en.wikipedia.org/w/api.php?origin=*&action=opensearch&search=
Para una búsqueda real, simplemente agregue un tema. Si necesita osos, por ejemplo, la URL se ve así:
//en.wikipedia.org/w/api.php?origin=*&action=opensearch&search=bears
Nos gustaría una función que tome un tema y devuelva la URL de búsqueda de Wikipedia completa. A medida que el usuario escribe, construimos la URL en función de su entrada.
Ramda concat
funciona muy bien aquí.
import { concat } from 'ramda'; const getWikipediaSearchUrlFor = concat( '//en.wikipedia.org/w/api.php?origin=*&action=opensearch&search=' );
concat
, fiel a su nombre, concatena cadenas y matrices. Está curry, por lo que proporcionar la URL como un argumento devuelve una función que espera una segunda cadena. ¡Vea mi artículo sobre curry si es nuevo!
Pon ese código en un módulo llamado getUrl.js
.
Ahora vamos a actualizar index.js
. Importa nuestros dos nuevos módulos, junto con pipe
y tap
desde Ramda.
import 'bootstrap/dist/css/bootstrap.min.css'; import { pipe, tap } from 'ramda'; import getInputValue from './getInputValue'; import getUrl from './getUrl'; const makeUrlFromInput = pipe( getInputValue, getUrl, tap(console.warn) ); const inputElement = document.querySelector('input'); inputElement.addEventListener('keyup', makeUrlFromInput);
Este nuevo código construye nuestra URL de solicitud a partir de la entrada del usuario y la registra a través de tap
.
Echale un vistazo.
Realización de la solicitud AJAX
El siguiente paso es mapear esa URL a una solicitud AJAX y recopilar la respuesta JSON.
Reemplazar makeUrlFromInput
con una nueva función searchAndRenderResults
,.
const searchAndRenderResults = pipe( getInputValue, getUrl, (url) => fetch(url) .then((res) => res.json()) .then(console.warn) );
¡No olvide cambiar también el oyente de su evento!
inputElement.addEventListener('keyup', searchAndRenderResults);
Aquí está nuestro resultado.
Hacer un componente de resultados
Ahora que tenemos JSON, creemos un componente que lo embellezca.
Agregue Results.js
a su directorio.
Consulte nuestra respuesta JSON de búsqueda en Wikipedia. Note su forma. Es una matriz con los siguientes índices:
- Consulta (lo que buscaste)
- Matriz de nombres de resultados
- Matriz de resúmenes
- Array of links to results
Our component can take an array of this shape and return a nicely formatted list. Through ES6 array destructuring, we can use that as our function signature.
Edit Results.js
export default ([query, names, summaries, links]) => ` Searching for "${query}"
${names.map( (name, index) => ` ${name}
${summaries[index]}
` )}
`;
Let’s go step by step.

Original text
- It’s a function that takes an array of our expected elements:
query
,names
,summaries
, andlinks
. - Using ES6 template literals, it returns an HTML string with a title and a list.
- Inside the
tags, so one for each.
- Inside those are
tags pointing to each result’s link. Each link opens in a new tab.
- Below the link is a paragraph summary.
we map
names
toImport this in
index.js
and use it like so:// ... import Results from './Results'; // ... const searchAndRenderResults = pipe( getInputValue, getUrl, (url) => fetch(url) .then((res) => res.json()) .then(Results) .then(console.warn) );
This passes the Wikipedia JSON to
Results
and logs the result. You should be seeing a bunch of HTML in your DevTools console!All that’s left is to render it to the DOM. A simple
render
function should do the trick.const render = (markup) => { const resultsElement = document.getElementById('results'); resultsElement.innerHTML = markup; };
Replace
console.warn
with therender
function.const searchAndRenderResults = pipe( getInputValue, getUrl, (url) => fetch(url) .then((res) => res.json()) .then(Results) .then(render) );
And check it out!
Each link should open in a new tab.
Removing Those Weird Commas
You may have noticed something off about our fresh UI.
It has extra commas! Why??
Template Literals
It’s all about how template literals join things. If you stick in an array, it’ll join it using the
toString()
method.See how this becomes joined?
const joined = [1, 2, 3].toString(); console.log(joined); // 1,2,3 console.log(typeof joined); // string
Template literals do that if you put arrays inside of them.
const nums = [1, 2, 3]; const msg = `My favorite nums are ${nums}`; console.log(msg); // My favorite nums are 1,2,3
You can fix that by joining the array without commas. Just use an empty string.
const nums = [1, 2, 3]; const msg = `My favorite nums are ${nums.join('')}`; console.log(msg); // My favorite nums are 123
Edit
Results.js
to use thejoin
method.export default ([query, names, summaries, links]) => `
Searching for "${query}"
- ${names .map( (name, index) => `
${name}
${summaries[index]}
` ) .join('')}
Now your UI’s much cleaner.
Fixing a Little Bug
I found a little bug while building this. Did you notice it?
Emptying the
input
throws this error.That’s because we’re sending an AJAX request without a search topic. Check out the URL in your Network tab.
That link points to a default HTML page. We didn’t get JSON back because we didn’t specify a search topic.
To prevent this from happening we can avoid sending the request if the
input
's empty.We need a function that does nothing if the
input
's empty, and does the search if it’s filled.Let’s first create a function called
doNothing
. You can guess what it looks like.const doNothing = () => {};
This is better known as
noOp
, but I likedoNothing
in this context.Next remove
getInputValue
from yoursearchAndRenderResults
function. We need a bit more security before using it.const searchAndRenderResults = pipe( getUrl, (url) => fetch(url) .then((res) => res.json()) .then(Results) .then(render) );
Import
ifElse
andisEmpty
from Ramda.import { ifElse, isEmpty, pipe, tap } from 'ramda';
Add another function,
makeSearchRequestIfValid
.const makeSearchRequestIfValid = pipe( getInputValue, ifElse(isEmpty, doNothing, searchAndRenderResults) );
Take a minute to absorb that.
If the input value’s empty, do nothing. Else, search and render the results.
You can gather that information just by reading the function. That’s expressive.
Ramda’s isEmpty function works with strings, arrays, objects.
This makes it perfect to test our input value.
ifElse
fits here because whenisEmpty
returns true,doNothing
runs. OtherwisesearchAndRenderResults
runs.Lastly, update your event handler.
inputElement.addEventListener('keyup', makeSearchRequestIfValid);
And check the results. No more errors when clearing the
input
!This tutorial was from mycompletely freecourse on Educative.io, Functional Programming Patterns With RamdaJS!
Please consider taking/sharing it if you enjoyed this content.
It’s full of lessons, graphics, exercises, and runnable code samples to teach you a basic functional programming style using RamdaJS.
Thank you for reading ❤️