Как да използвам API за търсене на Wikipedia за изграждане на потребителски интерфейс с RamdaJS

В този урок ще изградим потребителски интерфейс, използвайки API за публично търсене на Wikipedia заедно с някои JavaScript + RamdaJS.

Приготвяме се да започнем

Ето връзката към GitHub и връзката Codesandbox. Отворете терминала си и изберете директория, за да го клонирате.

git clone [//github.com/yazeedb/ramda-wikipedia-search](//github.com/yazeedb/ramda-wikipedia-search) cd ramda-wikipedia-search yarn install (or npm install) 

В masterбранша има завършен проект, така че проверете на startклона, ако искате да код заедно.

git checkout start

И стартирайте проекта!

npm start

Вашият браузър трябва автоматично да отвори localhost: 1234.

Получаване на входната стойност

Ето първоначалното приложение.

За да улови входа на потребителя, докато пише, нашият inputелемент се нуждае от слушател на събития.

Вашият src/index.jsфайл вече е свързан и готов за работа. Ще забележите, че сме импортирали Bootstrap за стилизиране.

Нека добавим фиктивен слушател на събития, за да стартираме нещата.

import 'bootstrap/dist/css/bootstrap.min.css'; const inputElement = document.querySelector('input'); inputElement.addEventListener('keyup', (event) => { console.log('value:', event.target.value); }); 

Знаем event.target.valueстандартния начин за достъп до стойността на даден вход. Сега показва стойността.

Как Рамда може да ни помогне да постигнем следното?

  • Грабнете event.target.value
  • Подстригване на изхода (пробел, водещ / последващ интервал)
  • По подразбиране е празен низ, ако undefined

Най pathOrфункцията всъщност може да се справи с първия и третия куршум точки. Отнема три параметъра: по подразбиране, пътя и данните.

Така че следното работи перфектно

import { pathOr } from 'ramda'; const getInputValue = pathOr('', ['target', 'value']); 

Ако event.target.valueе undefined, ще получим празен низ обратно!

Ramda също има trimфункция, която решава проблема с празното пространство.

import { pathOr, trim } from 'ramda'; const getInputValue = (event) => trim(pathOr('', ['target', 'value'], event)); 

Вместо да влагаме тези функции, нека използваме pipe. Вижте статията ми за тръбата, ако е нова за вас.

import { pathOr, pipe, trim } from 'ramda'; const getInputValue = pipe( pathOr('', ['target', 'value']), trim ); 

Сега имаме съставена функция, която взема eventобект, хваща го target.value, по подразбиране ''и го изрязва.

Красив.

Препоръчвам да съхранявате това в отделен файл. Може би да го извикате getInputValue.jsи да използвате синтаксиса по подразбиране за експортиране.

Получаване на URL адреса на Wikipedia

Към момента на написването URL адресът за търсене на API на Wikipedia е //en.wikipedia.org/w/api.php?origin=*&action=opensearch&search=

За действително търсене просто добавете тема. Ако имате нужда от мечки, например, URL адресът изглежда така:

//en.wikipedia.org/w/api.php?origin=*&action=opensearch&search=bears

Бихме искали функция, която взема тема и връща пълния URL адрес за търсене в Wikipedia. Тъй като потребителските типове изграждаме URL адреса въз основа на въведеното от тях.

Тук Рамда concatработи добре.

import { concat } from 'ramda'; const getWikipediaSearchUrlFor = concat( '//en.wikipedia.org/w/api.php?origin=*&action=opensearch&search=' ); 

concat, вярно на името си, обединява низове и масиви. Той се извива, така че предоставянето на URL адреса като един аргумент връща функция, която очаква втори низ. Вижте статията ми за кърирането, ако е нова!

Поставете този код в модул, наречен getUrl.js.

Сега нека актуализираме index.js. Импортирайте нашите два нови модула, заедно със pipeи tapот 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); 

Този нов код изгражда URL адреса на нашата заявка от въведеното от потребителя и го регистрира чрез tap.

Виж това.

Изпращане на заявка AJAX

Следващата стъпка е картографиране на този URL адрес в заявка AJAX и събиране на JSON отговора.

Заменете makeUrlFromInputс нова функция searchAndRenderResults,.

const searchAndRenderResults = pipe( getInputValue, getUrl, (url) => fetch(url) .then((res) => res.json()) .then(console.warn) ); 

Не забравяйте да смените и слушателя на вашите събития!

inputElement.addEventListener('keyup', searchAndRenderResults); 

Ето нашия резултат.

Създаване на компонент за резултати

Сега, когато имаме JSON, нека създадем компонент, който да го подобри.

Добавете Results.jsкъм вашата директория.

Погледнете назад към нашия отговор в JSON за търсене в Wikipedia. Обърнете внимание на формата му. Това е масив със следните индекси:

  1. Заявка (какво търсихте)
  2. Масив от имена на резултати
  3. Масив от обобщения
  4. 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, and links.
  • Using ES6 template literals, it returns an HTML string with a title and a list.
  • Inside the
      we map names to
    • 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.

    Import 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 the render 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 the join 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 like doNothing in this context.

    Next remove getInputValue from your searchAndRenderResults 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 and isEmpty 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 when isEmpty returns true, doNothing runs. Otherwise searchAndRenderResults 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 ❤️