Это пошаговое руководство по настройке Algolia для вашего сайта Gatsby с помощью React InstantSearch.js. Сначала мы реализовали бэкэнд Algolia, а затем интерфейс. В нашем репо ключи Algolia хранятся в Секретах Github и отправляются как переменные среды через Действия Github при развертывании приложения. В этом руководстве основное внимание уделяется реализации Algolia в существующем приложении Gatsby React.

Настройка серверной части Algolia

Давайте начнем с реализации Algolia Backend.

Готовый?

Набор.

Go!

  1. Создайте учетную запись в Algolia и получите 4 части информации:
  • Имя, которое вы дали указателю (в нашем случае "docs")
  • Ваш идентификатор приложения
  • Ваш ключ API только для поиска
  • Ваш ключ Admin API

2. Запустите (установите dotenv, только если вы его еще не используете):

$ gatsby-plugin-algolia react-instantsearch-dom dotenv

3. Добавьте свои ключи API в файл .env.production (это просто примеры ключей. Наши фактические ключи хранятся в секретах GitHub в репозитории).

GATSBY_ALGOLIA_APP_ID = KA4OJA9KAS
GATSBY_ALGOLIA_SEARCH_KEY=lkjas987ef923ohli9asj213k12n59a
ALGOLIA_ADMIN_KEY = lksa09sadkj1230asd09dfvj12309aj

4. Добавьте следующий код в файл gatsby-config.js:

const queries = require('./src/utils/algolia');
require('dotenv').config({
  path: `.env.${process.env.NODE_ENV}`,
});
module.exports = {
  siteMetadata: {
  title: 'your title',
  description: 'your description',
  author: '@gatsbyjs',
  siteUrl: 'https://learning.getpostman.com', // example url
},
plugins: [
  'gatsby-plugin-react-helmet',
 {
  resolve: `gatsby-plugin-algolia`,
  options: {
    appId: process.env.GATSBY_ALGOLIA_APP_ID,
    apiKey: process.env.ALGOLIA_ADMIN_KEY,
    queries,
    chunkSize: 10000, // default: 1000
 },

Примечание. Вы можете убедиться, что appID имеет красный цвет из файла .env, запустив:

$ console.log(process.env.GATSBY_ALGOLIA_APP_ID)
$ gatsby develop

Путь в gatsby-config.js должен быть:

require('dotenv').config({
  path: `.env.${process.env.NODE_ENV}`,
});

4. Создайте файл в src / utils / algolia.js.

Вы можете получить данные, которые Algolia должна проиндексировать, прямо со слоя Gatsby's GraphQL. Вы можете сделать это, экспортировав массив объектов из src / utils / algolia.js. Каждый объект содержит требуемый запрос GraphQL и необязательное имя индекса, функцию преобразователя и объект настроек.

Свойство запроса: строка запроса GraphQL
Преобразователь: функция принимает данные запроса и преобразует их в массив объектов, которые станут записями индекса Algolia.

const pageQuery = `{
docs: allMarkdownRemark(
  filter: {
    fileAbsolutePath: { regex: "/docs/" },
  }
 ) {
  edges {
    node {
      frontmatter {
        title
      contextual_links {
        type
        name
        url
      }
    }
    excerpt(pruneLength: 5000)
   }
  }
 }
}`
const flatten = arr =>
  arr.map(({ node: { frontmatter, ...rest } }) => ({
  ...frontmatter,
  ...rest,
}))
const settings = { attributesToSnippet: [`excerpt:20`] }
const queries = [{
  query: pageQuery,
  transformer: ({ data }) => flatten(data.docs.edges),
  indexName: `docs`,
  settings,
}]
module.exports = queries

5. Gatsby development запускает сервер:

$ Run npm: build -  builds the static page

Теперь ваши "документы" индексов Algolia должны быть заполнены данными.

Советы по отладке:
- Если вы не можете получить какие-либо данные в Algolia, console.log (запросы) и проверьте, отображается ли нужная информация.
- Если это не так, запустите приложение и перейдите на localhost: 8000 / __ graphql. Вы можете скопировать и вставить сюда свой запрос graphql и проверить, какие данные возвращаются.

Интерфейс Algolia

Потрясающий! Наш бэкэнд настроен, у вас есть объекты в вашем индексе Algolia, теперь позвольте нам запустить Frontend. На полпути 👏

  1. Нам нужно 2 файла в src / components / Search /
  • SearchPreview.jsx - содержит наш собственный код
  • _search.scss - для стилизации

В searchPreview.jsx вы можете создать настраиваемый SearchBox и определить, что Hits (результаты, возвращаемые из Algolia) отображаются только тогда, когда пользователь вводит текст в SearchBox. В противном случае Algolia по умолчанию будет отображать все проиндексированные результаты при загрузке страницы. Вот как выглядит код:

import React from 'react';
import { connectSearchBox, connectHits } from 'react-instantsearch-dom';
import './_search.scss';
const SearchBox = ({ currentRefinement, refine }) => (
  <div className="ais-SearchBox">
  <form noValidate action="" role="search" className="ais-SearchBox-form">
    <input 
      className="ais-SearchBox-input"
      type="search"
      value={currentRefinement} 
      onChange={(event) => refine(event.currentTarget.value)}
    />
  </form>
</div>
);
export const CustomSearchBox = connectSearchBox(SearchBox);
// print out first and last characters around search term
const getSnippet = (excerpt, match) => {
const index = excerpt.indexOf(match);
return excerpt.substring(index - 50, index + 50);
};
// only display Hits when user types in SearchBox
const Hits = ({ hits }) => (
<ul className="style">
  {hits.map((hit) => (
    <li key={hit.title}>
      <a href={hit.fields.slug}>
        {hit.title}
        <p>{`...${getSnippet(hit.excerpt,  hit._highlightResult.title.matchedWords[0])}...`}
       </p>
     </a>
    </li>
  ))}
</ul>
);
export const CustomHits = connectHits(Hits);

Затем мы включили Algolia SearchBox в наш файл src / components / Header / Header.jsx, потому что нам нужна панель поиска по центру панели навигации Bootstrap4.

Все, что нам нужно для Algolia Frontend

  1. Импортируйте из Алголии все, что нам нужно
import algoliasearch from 'algoliasearch/lite';
import { 
  InstantSearch, 
  SearchBox, 
  Hits, 
  Configure 
 } from 'react-instantsearch-dom';
import { CustomHits } from '../Search/searchPreview';

2. Устанавливаем состояние, что поле searchInput пусто

constructor(props) {
  super(props);
  this.state = {
    isToggledOn: false,
    hasInput: false,
    refresh: false,
  };
}

3. Мы импортируем виджет InstantSearch и передаем наш ключ API и AppID через searchClient.

Примечание.
В Algolia есть несколько функций InstantSearches для различных библиотек и фреймворков. Мы используем React InstantSearch. В зависимости от того, какой InstantSearch вы используете, вам доступны разные варианты для разных виджетов. Вначале мне это было непонятно.

В нашем виджете React InstantSearch я настроил InstantSearch для отображения максимум 5 результатов поиска:

const searchClient = algoliasearch('4A5N71XH', 'bf5cf4783437b12c2dca33724c9c04');
<InstantSearch
  searchClient={searchClient}
  indexName="docs"
  refresh={refresh}
  >
  <Configure hitsPerPage={5} />
</InstantSearch>

4. Теперь мы включаем собственно SearchBox. На данный момент React InstantSearch не имеет возможности удалить кнопки отправки / сброса по умолчанию, поэтому мы скрываем их с помощью CSS. Затем мы определяем событие onKeyUp, которое устанавливает состояние hasInput, когда пользователь начинает вводить текст в SearchBox.

<InstantSearch
  searchClient={searchClient}
  indexName="docs"
  refresh={refresh}
>
  <Configure hitsPerPage={5} />
  <SearchBox
    className="searchbox"
    class="ais-SearchBox-input"
    submit={<></>}
    reset={<></>}
    translations={{
      placeholder: 'Search Postman Docs',
    }}
    onKeyUp={(event) => {
      this.setState({
        hasInput: event.currentTarget.value !== '',
       });
    }}
  />
</InstantSearch>

5. Затем мы включили наш виджет CustomHits, который принимает хиты, возвращаемые из Algolia, которые мы определяем в нашем файле searchPreview.jsx.

Показывать результаты только тогда, когда пользователь начинает печатать

Мы оборачиваем виджет CustomHits в div, который принимает текущий setState как className, потому что виджет CustomHits не принимает имена классов изначально, и мы хотим отображать Hits только тогда, когда пользователь вводит текст в SearchBox.

<SearchBox
  className="searchbox"
  class="ais-SearchBox-input"
  submit={<></>}
  reset={<></>}
  translations={{
    placeholder: 'Search Postman Docs',
  }}
  onKeyUp={(event) => {
    this.setState({
    hasInput: event.currentTarget.value !== '',
    });
   }}
/>
 {/*forcefeed className because component does not accept natively as prop*/}
  <div className={!hasInput ? 'input-empty' : 'input-value'}>
    <CustomHits hitComponent={Hits} />
  </div>
</InstantSearch>

6. Затем мы заключаем наш InstantSearch в ClickOutHandler, чтобы закрыть контейнер обращений, когда пользователь щелкает мышью вне SearchResults.

const ClickOutHandler = require('react-onclickout');
onClickOut = () => {
  document.getElementsByClassName('ais-SearchBox-input')[0].value = '';
  this.setState(() => ({
    hasInput: false,
  }));
}
 <ClickOutHandler onClickOut={this.onClickOut}>
 <InstantSearch
    searchClient={searchClient}
    indexName="docs"
    refresh={refresh}
  >
   ...
 </InstantSearch>
</ClickOutHandler>

7. Наконец, мы стилизуем наш Sarchbox и Hits. Вы можете стилизовать их, добавив classNames или сославшись на classNames Algolia и добавив наш собственный стиль, перезаписав стиль по умолчанию. Вот как выглядит наш CSS для SearchBox:

.searchbox {
  input {
    background-color:#f5f5f5;
    border: 0;
    padding: 13px 24px;
    border-radius: 3px;
    width: 100%;
  }
  ::placeholder {
    color: #1c272b;
    font-size: 14px;
    font-weight: 600;
  }
  .ais-SearchBox-submit, .ais-SearchBox-reset {
    display: none;
  }
}

8. Последнее, что нужно включить, это, конечно, поддержку IE11 для Aloglia в наш файл seo.jsx. Передаем сценарий в шлеме Гэтсби.

<Helmet>
  {/* Algolia IE11 support */}
  <script src="https://polyfill.io/v3/polyfill.min.js?features=default,Array.prototype.find,Array.prototype.includes" />
</Helmet>

И готово!

Поздравляю! Теперь вы настроили Algolia React InstantSearch в своем приложении Gatsby React. Вот наша реализация Algolia в Учебном центре Postman.

Дайте мне знать, что вы думаете, или, если у вас есть вопросы, напишите мне в Twitter 👩‍💻 Мне нравится читать / твитить / ретвитнуть все виды технического / кодового контента 🏄‍♀️