У цьому підручнику ми створимо інтерфейс, використовуючи 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. Зверніть увагу на його форму. Це масив із наступними індексами:
- Запит (що ви шукали)
- Масив імен результатів
- Масив конспектів
- 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 ❤️