简体   繁体   English

使用自动完成功能获取 API 数据和过滤搜索输入

[英]Fetch API data with react and filter search input with autocomplete

I have a question regarding a React filter search input.我有一个关于 React 过滤器搜索输入的问题。

I have two Components the the moment.我现在有两个组件。

FirstPageComponent.js 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"]} />
  }
}

and

AutoComplete.js自动完成.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>
    )
  }
}
  • I basically want to know if i'm approaching this the right way.我基本上想知道我是否以正确的方式接近这个。 I want to make a dynamic request for movie titles from fetch(” https://themovie.db ”) API.我想从 fetch(” https://themovie.db ”) API 动态请求电影标题。

  • Send down the movie titles as props and then filter the values in autocomplete component if the user input is similar to the movie title props.如果用户输入类似于电影标题道具,则将电影标题作为道具发送,然后过滤自动完成组件中的值。

Am i thinking about this the right way?我是否以正确的方式思考这个问题? I've tried to have the fetch call in the same component as AutoComplete but haven't gotten it to work as i want it to.我试图在与 AutoComplete 相同的组件中进行 fetch 调用,但没有让它按我想要的方式工作。 How would you setup the component structure if you'd be solving this issue for example?例如,如果您要解决此问题,您将如何设置组件结构?

Feel free to ask if there're any confusions.随意询问是否有任何混淆。

Thanks谢谢

These are my assumptions about the above code, let me know if any are incorrect.这些是我对上述代码的假设,如果有任何不正确,请告诉我。

  • You're doing an initial API request for a list of movies by search term.您正在执行初始 API 请求,以按搜索词列出电影列表。 That search term is given outside of the code above and doesn't change by any mechanism above.该搜索词是在上面的代码之外给出的,并且不会被上面的任何机制改变。
  • You're further filtering the data returned by the API request dynamically via the AutoComplete component.您将通过AutoComplete组件动态过滤 API 请求返回的数据。

Most of your React code here looks pretty good, but I've got some recommendations:这里的大部分 React 代码看起来都不错,但我有一些建议:

  1. In general, I find it's best to keep the list of things completely separate, so I would create a separate MovieList function component that simply takes an array of movie objects, and a titleFilter string and renders them.一般来说,我发现最好将事物列表完全分开,因此我将创建一个单独的MovieList function 组件,它只需要一个movie对象数组和一个titleFilter字符串并呈现它们。
  2. componentDidMount doesn't take arguments. componentDidMount不采用 arguments。 searchTerm should be a prop of FirstPageComponent (presumably set by the parent component by some kind of selection or user input) searchTerm应该是FirstPageComponent的一个 prop(可能是由父组件通过某种选择或用户输入设置的)
  3. I'd rename AutoComplete to TitleFilter or the like.我会将AutoComplete重命名为TitleFilter等。 It's not really auto-completing, it's more of a filter field.它并不是真正的自动完成,它更像是一个过滤器字段。
  4. This line: if (loading && userInput) { will result in displaying no movies when the user hasn't yet filled in text into the filter field.这一行: if (loading && userInput) {将导致当用户尚未在过滤器字段中填写文本时不显示电影。 I'm not sure that is what you would want.我不确定那是你想要的。
  5. This line is a bit misleading: <p>Couldn't find any movies. Try searching for another movie.</p>这行有点误导: <p>Couldn't find any movies. Try searching for another movie.</p> <p>Couldn't find any movies. Try searching for another movie.</p> because you could have just filtered out all the results returned. <p>Couldn't find any movies. Try searching for another movie.</p>因为您可能已经过滤掉了所有返回的结果。 In this case, it wasn't that you couldn't find movies, it's that your filter is too restrictive.在这种情况下,不是你找不到电影,而是你的过滤器限制太多。
  6. For the onClick handler, I'm not sure such a general approach is best.对于onClick处理程序,我不确定这种通用方法是否最好。 It could create a strange interaction if you were to somehow click on the <ul> , for example.例如,如果您以某种方式单击<ul> ,它可能会产生奇怪的交互。 To improve this, I'd recommend each movie row component implement its own onClick and call a function to set the filter.为了改善这一点,我建议每个电影行组件实现自己的onClick并调用 function 来设置过滤器。
  7. You're going to have to deal with pagination on this, I'd bet.我敢打赌,您将不得不处理分页。 Check your API and see what it does for that and make sure you're accounting for it.检查您的 API 并查看它为此做了什么,并确保您正在考虑它。

Small nits:小尼特:

  1. userInput: e.currentTarget.value, could be shortened to userInput, , which is shorthand for userInput: userInput, (you already have a variable named userInput .) userInput: e.currentTarget.value,可以缩写为userInput, ,它是userInput: userInput,的简写(你已经有一个名为userInput的变量。)
  2. For key props, an actual unique id would be better, in the case you change your filtering and index numbers don't line up with the unique rows you're rendering anymore.对于key道具,实际的唯一 id 会更好,以防您更改过滤并且索引号不再与您正在呈现的唯一行对齐。
  3. I like to go ahead and create a separate component for each row, so I'd make a MovieRow function component which takes a movie object and renders it.我喜欢提前 go 并为每一行创建一个单独的组件,所以我会制作一个MovieRow function 组件,它需要一个movie object 并渲染它。 It just keeps the code a bit cleaner.它只是使代码更简洁。 (and makes #6 above easier to implement) (并使上面的#6更容易实现)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM