Начиная

Приложение автозаполнения — это то, что позволяет вам легко искать продукты, просто вводя соответствующий текст к фактическим названиям продуктов. В нашем случае мы будем работать над приложением для поиска продуктов питания, которое легко позволит вам искать соответствующие продукты питания.

Я уже создал структуру и важные стили приложения, используя React и SASS, мы будем добавлять логику поиска и автозаполнения.

Я использовал интерфейс командной строки create-react-app для создания и управления проектом приложения.

Вы можете получить полный исходный код с Github.

Домашний компонент

Вы можете представить его как многостраничное приложение с домашней страницей, на которой есть компонент поиска для поиска различных продуктов.

Обратите внимание, что все стили SASS представлены в репозитории проекта Github, поэтому рассмотрите возможность их получения.

/* pages/home.jsx */
import React from "react";
import Search from "../components/search";

export default class HomePage extends React.Component {
  render() {
    return (
      <div className="page">
        <div className="page-container">
          <div className="container">
            <Search />
          </div>
        </div>
      </div>
    );
  }
}

И обязательно визуализируйте компонент в App.jsx.

/* App.jsx */
import React from "react";
import logo from "./logo.svg";
import "./App.scss";
import HomePage from "./pages/home";

function App() {
  return (
    <div className="App">
      <HomePage />
    </div>
  );
}

export default App;

В приложении create-реагировать на приложение Project App.jsx по умолчанию отображается в DOM на index.js.

Давайте добавим панель поиска в середину нашей домашней страницы.

Бар поиска еды

Я уже создал элегантный дизайн для панели поиска, поэтому рассмотрите возможность получения файлов стилей из репозитория Github.

Теперь создайте папку компонентов внутри src/ и создайте папку search/ для панели поиска.

Создайте index.jsx в качестве основной точки входа компонента поиска.

import React from "react";

import "./style.scss";
import Popup from "./popup";

export default class Search extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
    };
  }

  render() {
    return (
      <div className="search">
        <div className="search-container">
          <div className="title">Type Food Name</div>
          <div className="content">
            <input
              type="text"
              placeholder="Food"
            />
            <Popup isOpen={true} items={[{name: "Lasagna"}, {name: "Noodles"}]} />
          </div>
        </div>
      </div>
    );
  }
}

Здесь мы добавили простой компонент поиска, который отображает всплывающее окно внизу. Компонент поиска довольно прост, поскольку все, что он делает, — это визуализирует ввод текста с компонентом всплывающего окна в нижней части ввода поиска.

Компонент Popup будет отвечать за отображение раскрывающегося всплывающего окна (Popover), которое отображает результат поиска, в этом случае он будет отображать результат поиска с автозаполнением продуктов питания.

/* components/search/popup.jsx */
import React from "react";

export default class Popup extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    const { items, isOpen } = this.props;
    //Do not show popup
    if (!isOpen) return null;
    return (
      <div className="popup">
        <div className="container">
          <div className="content">
            {items &&
              items.map((item, idx) => {
                return (
                  <div className="item" key={idx}>
                    {item.name}
                  </div>
                );
              })}
            {!items && <div className="warning">Nothing Found!</div>}
          </div>
          <div className="footer">Type Keyword to search for food</div>
        </div>
      </div>
    );
  }
}

Компонент Popup принимает список элементов для отображения в раскрывающемся списке вместе с опорой isOpen, чтобы отображать всплывающее окно или нет (показать и скрыть).

Из компонента поиска мы предоставляем простые тестовые данные в виде списка элементов для отображения во всплывающем окне. Вы можете проверить это, сохранив и открыв URL-адрес своего сервера разработки в браузере.

Получить автозаполнение

Это зависит от того, что ваше приложение фактически достигает конечной точки и извлекает данные о продуктах питания, но в этом случае мы будем использовать простой файл food.json, который имитирует конечную точку API для предоставления нам данных о продуктах питания.

Вот как выглядит ответ API-интерфейса food.json.

{
  "foods": [
    {
      "name": "Lasagna",
      "price": "12$"
    },
    {
      "name": "Noodles",
      "price": "8$"
    },
    {
      "name": "Chicken Tikka",
      "price": "16$"
    },
    {
      "name": "Soup",
      "price": "6$"
    }
  ]
}

Вы можете добавить более подробную информацию о еде, например, о ее типе и о том, доступна ли она в меню на сегодня или нет.

Обязательно инициализируйте состояние с правильными значениями.

constructor(props) {
  super(props);
  this.state = {
    isPopupOpen: false,
    foods: [],
    errors: [],
    isError: false,
    foundFoods: []
  };
}

Лучший сценарий для извлечения данных о еде и поиска их для автозаполнения — это сначала получить их, когда компонент поиска впервые монтируется в DOM, чтобы мы могли избежать многократного извлечения данных, когда пользователь взаимодействует с веб-страницей, что может вызвать React повторный рендеринг, и мы не хотим попадать в конечную точку нашего сервера несколько раз с необходимостью.

/*search/index.jsx*/
...
constructor(props) {
  super(props);
  this.state = {
    foods: [],
  };
}
//Async keyword for working with Promises.
async fetchData() {
  //Use ES6 fetch function to get json 
  const foods = await fetch("/resources/food.json").catch(err => {
    this.setError("Cannot Load Food Data from Server!");
  });
  //Set foods in the state
  this.setState({ foods: (await foods.json()).foods });
}

//Fetch data when the component is firstly mounted 
componentDidMount() {
  //Fetch & hold data on the state
  this.fetchData();
}
...

Теперь мы получили данные в состоянии во-первых, когда компонент монтируется в DOM. Давайте попробуем найти в массиве искомое ключевое слово пользователем.

searchFood(keyword) {
  //Get foods array list 
  const { foods } = this.state;
  //Make sure to safely Escape keyword since it is coming from user's input
  keyword = RegExp.escape(keyword.toLowerCase());
  /*We generate a Regular Expression from the input keyword.
    The Regex allows for having at least one character matched from the actual food name.
    This way we can add autocomplete functionality.
  */
  const pattern = `[A-Za-z.\s]*${keyword}[A-Za-z.\s]*`;
  //Generate a Regex instance from string pattern
  const matchRegex = new RegExp(pattern);
  //Filter found foods that matches the current Regex
  const foundFoods = foods.filter(item =>
    matchRegex.test(item.name.toLowerCase())
  );
  //Set found foods on the state.
  this.setState({ foundFoods });
}

Осталось только запускать метод searchFood всякий раз, когда пользователь что-то вводит в строке поиска, поэтому нам нужно прослушивать событие onChanage на входе.

onInputChange(e) {
  const keyword = e.target.value;
  this.searchFood(keyword);
}

onInput(e) {
  if (e.target.value !== "") this.showPopup();
  else this.hidePopup();
}

showPopup() {
  this.setState({ isPopupOpen: true });
}

hidePopup() {
  this.setState({ isPopupOpen: false });
}

Метод onInput будет запущен, когда пользователь начнет вводить ввод, чтобы мы могли отобразить всплывающее окно, чтобы показать результат поиска, нам также нужно убедиться, что значение не является пустым.

И мы меняем состояние isPopupOpen двумя независимыми методами, чтобы показать или скрыть всплывающее окно поиска.

Наконец, нам нужно управлять ошибками, устанавливая и очищая их в состоянии, чтобы вы могли информировать пользователя о любых технических ошибках или проблемах, связанных с поиском.

setError(msg) {
  this.setState(prevState => ({
    errors: [...prevState.errors, msg],
    isError: true
  }));
}

clearAllErrors() {
  this.setState({ errors: [], isError: false });
}

Обязательно правильно визуализируйте ошибки, чтобы сделать ошибки более удобными и информативными, если в процессе поиска возникнут какие-либо ошибки.

Наконец, просто передайте правильные значения состояния, чтобы отобразить всплывающее окно и правильно перехватить события ввода.

...
render() {
  const { isPopupOpen, foundFoods } = this.state;
  return (
    <div className="search">
      <div className="search-container">
        <div className="title">Type Food Name</div>
        <div className="content">
          <input
            type="text"
            placeholder="Food"
            onInput={this.onInput.bind(this)}
            onChange={this.onInputChange.bind(this)}
          />
          <Popup isOpen={isPopupOpen} items={foundFoods} />
        </div>
      </div>
    </div>
  );
}
...

Вы можете попробовать найти еду в файле food.json и посмотреть, работает ли автозаполнение идеально, рассмотрите возможность получения данных из конечной точки API для надежного поиска.