Получать данные API с помощью реакции и фильтровать ввод с автозаполнением - PullRequest
0 голосов
/ 16 октября 2019

У меня есть вопрос, касающийся входных данных поиска фильтра React.

В настоящий момент у меня есть два компонента.

FirstPageComponent.js

import React from "react"
import AutoComplete from "./AutoComplete"

export class FirstPageComponent extends React.Component {
  constructor() {
    super()
    this.state = {
      rows: [],
      loading: true,
    }
  }
  async componentDidMount(searchTerm = "marvel") {
    await fetch(
      "https://api.themoviedb.org/3/search/movie?api_key=&query=" +
        searchTerm
    )
      .then(response => response.json())
      .then(responseData => {
        this.setState({
          rows: responseData.results,
          loading: false,
        })
      })
      .catch(error => {
        console.log("Error fetching and parsing data", error)
      })
  }
  render() {
    console.log(this.state.rows)
    return <AutoComplete movies={["hej"]} />
  }
}

и

AutoComplete.js

import React from "react"

export default class AutoComplete extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      rows: [],
      loading: false,
      userInput: "",
    }
  }

  onChange = e => {
    const { movies } = this.props
    const userInput = e.currentTarget.value

    const rows = movies.filter(
      suggestion =>
        suggestion.toLowerCase().indexOf(userInput.toLowerCase()) > -1
    )

    this.setState({
      rows,
      loading: true,
      userInput: e.currentTarget.value,
    })
  }

  onClick = e => {
    this.setState({
      rows: [],
      loading: false,
      userInput: e.currentTarget.innerText,
    })
  }

  render() {
    const {
      onChange,
      onClick,
      state: { rows, loading, userInput },
    } = this
    let moviesListComponent
    if (loading && userInput) {
      if (rows.length) {
        moviesListComponent = (
          <ul>
            {rows.map((movie, index) => {
              return (
                <li key={index} onClick={onClick}>
                  {movie}
                </li>
              )
            })}
          </ul>
        )
      } else {
        moviesListComponent = (
          <>
            <p>Couldn't find any movies. Try searching for another movie.</p>
          </>
        )
      }
    }

    return (
      <React.Fragment>
        <input type="search" onChange={onChange} value={userInput} />
        {moviesListComponent}
      </React.Fragment>
    )
  }
}
  • Я в основном хочу знать, правильно ли я подхожу к этому. Я хочу сделать динамический запрос для названий фильмов из fetch (”https://themovie.db”) API.

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

Думаю ли я об этом правильно? Я попытался вызвать вызов fetch в том же компоненте, что и AutoComplete, но еще нетчтобы он работал так, как я хочу. Как бы вы настроили структуру компонентов, если бы, например, решали эту проблему?

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

Спасибо

1 Ответ

1 голос
/ 16 октября 2019

Это мои предположения относительно приведенного выше кода, дайте мне знать, если какой-либо из них неправильный.

  • Вы выполняете первоначальный запрос API для списка фильмов по поисковому запросу. Этот поисковый термин задан вне приведенного выше кода и не изменяется ни одним из вышеперечисленных механизмов.
  • Дальнейшая фильтрация данных, возвращаемых запросом API, динамически через компонент AutoComplete.

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

  1. В общем, я считаю, что лучше держать список вещей совершенно отдельно, поэтому ясоздаст отдельный функциональный компонент MovieList, который просто принимает массив объектов movie и строку titleFilter и отображает их.
  2. componentDidMount не принимает аргументы. searchTerm должен быть опорой FirstPageComponent (предположительно установленной родительским компонентом посредством какого-либо выбора или пользовательского ввода)
  3. Я бы переименовал AutoComplete в TitleFilter или тому подобное. На самом деле это не автоматическое заполнение, это скорее поле фильтра.
  4. Эта строка: if (loading && userInput) { приведет к тому, что фильмы не будут отображаться, когда пользователь еще не заполнил текст в поле фильтра. Я не уверен, что это то, что вам нужно.
  5. Эта строка немного вводит в заблуждение: <p>Couldn't find any movies. Try searching for another movie.</p>, поскольку вы могли только что отфильтровать все возвращенные результаты. В данном случае дело не в том, что вы не можете найти фильмы, а в том, что ваш фильтр слишком ограничен.
  6. Для обработчика onClick я не уверен, что такой общий подход лучше. Это может создать странное взаимодействие, если вы, например, нажмете на <ul>. Чтобы улучшить это, я бы порекомендовал каждому компоненту строки фильма реализовать свой собственный onClick и вызвать функцию для установки фильтра.
  7. В этом вам придется разбираться с нумерацией страниц, держу пари,Проверьте свой API и посмотрите, что он делает для этого, и убедитесь, что вы его учитываете.

Маленькие гниды:

  1. userInput: e.currentTarget.value, можно сократить до userInput,, что является сокращением для userInput: userInput, (у вас уже есть переменная с именем userInput.)
  2. Для key реквизитов, фактический уникальный идентификатор будет лучше, если вы измените свою фильтрацию и индексчисла больше не совпадают с уникальными строками, которые вы визуализируете.
  3. Я хотел бы продолжить и создать отдельный компонент для каждой строки, поэтому я бы сделал функциональный компонент MovieRow, который принимаетmovie объект и отображает его. Это просто делает код немного чище. (и упрощает реализацию № 6 выше)
...