Як використовувати API пошуку Wikipedia для побудови користувальницького інтерфейсу з RamdaJS

У цьому підручнику ми створимо інтерфейс, використовуючи API загальнодоступного пошуку Вікіпедії разом із деякими 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
  • Обрізати вихідні дані (пробіли, що ведуть / закінчують пробіл)
  • За замовчуванням порожній рядок if 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-адреси Вікіпедії

На момент написання статті URL-адреса пошуку API Вікіпедії //en.wikipedia.org/w/api.php?origin=*&action=opensearch&search=

Для реального пошуку просто додайте тему. Наприклад, якщо вам потрібні ведмеді, URL-адреса виглядає так:

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

Нам потрібна функція, яка бере тему та повертає повну URL-адресу пошуку у Вікіпедії. Як типи користувачів, ми створюємо 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. Імпортуйте наші два нових модулі, разом із Ramda pipeта tapназад.

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. Зверніть увагу на його форму. Це масив із наступними індексами:

  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 ❤️