Sådan bruges Wikipedia's API til at oprette en brugergrænseflade med RamdaJS
I denne vejledning bygger vi et brugergrænseflade ved hjælp af Wikipedia's offentlige søgnings-API sammen med noget JavaScript + RamdaJS.
Kom godt i gang
Her er GitHub-linket og Codesandbox-linket. Åbn din terminal, og vælg en mappe for at klone den.
git clone [//github.com/yazeedb/ramda-wikipedia-search](//github.com/yazeedb/ramda-wikipedia-search) cd ramda-wikipedia-search yarn install (or npm install)
Den master
gren har det færdige projekt, så tjek den start
gren, hvis du ønsker at kode sammen.
git checkout start
Og start projektet!
npm start
Din browser skal automatisk åbne localhost: 1234.
Sådan får du inputværdien
Her er den indledende app.
For at fange brugerens input, mens de skriver, har vores input
element brug for en lytter til begivenheder.
Din src/index.js
fil er allerede tilsluttet og klar til at gå. Du vil bemærke, at vi importerede Bootstrap til styling.
Lad os tilføje en dummy begivenhedslytter for at få tingene i gang.
import 'bootstrap/dist/css/bootstrap.min.css'; const inputElement = document.querySelector('input'); inputElement.addEventListener('keyup', (event) => { console.log('value:', event.target.value); });
Vi ved, at event.target.value
det er standardmetoden til at få adgang til en indgangs værdi. Nu viser den værdien.
Hvordan kan Ramda hjælpe os med at opnå følgende?
- Tag fat
event.target.value
- Trim output (strip ledende / bageste hvidt mellemrum)
- Som standard er tom streng hvis
undefined
Den pathOr
funktion kan faktisk håndtere den første og tredje punktform. Det tager tre parametre: standard, sti og data.
Så følgende fungerer perfekt
import { pathOr } from 'ramda'; const getInputValue = pathOr('', ['target', 'value']);
Hvis det event.target.value
er undefined
, får vi en tom streng tilbage!
Ramda har også en trim
funktion, så det løser vores whitespace-problem.
import { pathOr, trim } from 'ramda'; const getInputValue = (event) => trim(pathOr('', ['target', 'value'], event));
I stedet for at indlejre disse funktioner, lad os bruge pipe
. Se min artikel om rør, hvis den er ny for dig.
import { pathOr, pipe, trim } from 'ramda'; const getInputValue = pipe( pathOr('', ['target', 'value']), trim );
Vi har nu en sammensat funktion, der tager et event
objekt, griber det target.value
, som standard ''
og trimmer det.
Smuk.
Jeg anbefaler at gemme dette i en separat fil. Måske kalde det getInputValue.js
og brug standardeksportsyntaxen.
Henter Wikipedia URL
I skrivende stund er Wikipedia's API-søgnings-URL //en.wikipedia.org/w/api.php?origin=*&action=opensearch&search=
For en faktisk søgning skal du bare tilføje et emne. Hvis du f.eks. Har brug for bjørne, ser URL'en sådan ud:
//da.wikipedia.org/w/api.php?origin=*&action=opensearch&search=bears
Vi vil gerne have en funktion, der tager et emne og returnerer den fulde Wikipedia-søgnings-URL. Når brugeren skriver, bygger vi URL'en baseret på deres input.
Ramda concat
fungerer pænt her.
import { concat } from 'ramda'; const getWikipediaSearchUrlFor = concat( '//en.wikipedia.org/w/api.php?origin=*&action=opensearch&search=' );
concat
, tro mod sit navn, sammenkædes strenge og arrays. Det er curried, så levering af URL'en som et argument returnerer en funktion, der forventer en anden streng. Se min artikel om karry, hvis den er ny!
Sæt koden i et kaldet modul getUrl.js
.
Lad os nu opdatere index.js
. Importer vores to nye moduler sammen med pipe
og tap
fra 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);
Denne nye kode konstruerer vores anmodnings-URL fra brugerens input og logger den via tap
.
Tjek det ud.
At lave AJAX-anmodningen
Næste trin er at kortlægge denne URL til en AJAX-anmodning og indsamle JSON-svaret.
Erstat makeUrlFromInput
med en ny funktion searchAndRenderResults
,.
const searchAndRenderResults = pipe( getInputValue, getUrl, (url) => fetch(url) .then((res) => res.json()) .then(console.warn) );
Glem ikke at skifte din begivenhedslytter også!
inputElement.addEventListener('keyup', searchAndRenderResults);
Her er vores resultat.
Lav en resultatkomponent
Nu hvor vi har JSON, lad os oprette en komponent, der pynter den op.
Føj Results.js
til din mappe.
Se tilbage på vores Wikipedia-søgning JSON-svar. Bemærk dens form. Det er en matrix med følgende indekser:
- Forespørgsel (hvad du søgte efter)
- Array af resultatnavne
- Resume af resuméer
- 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.
- 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 ❤️