最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Fetch API data with react and filter search input with autocomplete - Stack Overflow

programmeradmin2浏览0评论

I have a question regarding a React filter search input.

I have two Components the the moment.

FirstPageComponent.js

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

export class FirstPageComponent extends React.Component {
  constructor() {
    super()
    this.state = {
      rows: [],
      loading: true,
    }
  }
  async ponentDidMount(searchTerm = "marvel") {
    await fetch(
      "=&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

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(””) API.

  • Send down the movie titles as props and then filter the values in autoplete ponent 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 ponent as AutoComplete but haven't gotten it to work as i want it to. How would you setup the ponent structure if you'd be solving this issue for example?

Feel free to ask if there’re any confusions.

Thanks

I have a question regarding a React filter search input.

I have two Components the the moment.

FirstPageComponent.js

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

export class FirstPageComponent extends React.Component {
  constructor() {
    super()
    this.state = {
      rows: [],
      loading: true,
    }
  }
  async ponentDidMount(searchTerm = "marvel") {
    await fetch(
      "https://api.themoviedb/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

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.

  • Send down the movie titles as props and then filter the values in autoplete ponent 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 ponent as AutoComplete but haven't gotten it to work as i want it to. How would you setup the ponent structure if you'd be solving this issue for example?

Feel free to ask if there’re any confusions.

Thanks

Share Improve this question asked Oct 16, 2019 at 12:52 erikos93erikos93 6872 gold badges13 silver badges28 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 3

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. 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 ponent.

Most of your React code here looks pretty good, but I've got some remendations:

  1. In general, I find it's best to keep the list of things pletely separate, so I would create a separate MovieList function ponent that simply takes an array of movie objects, and a titleFilter string and renders them.
  2. ponentDidMount doesn't take arguments. searchTerm should be a prop of FirstPageComponent (presumably set by the parent ponent by some kind of selection or user input)
  3. I'd rename AutoComplete to TitleFilter or the like. It's not really auto-pleting, 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. 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> because you could have just filtered out all the results returned. 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. It could create a strange interaction if you were to somehow click on the <ul>, for example. To improve this, I'd remend each movie row ponent implement its own onClick and call a function to set the filter.
  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.

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.)
  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.
  3. I like to go ahead and create a separate ponent for each row, so I'd make a MovieRow function ponent which takes a movie object and renders it. It just keeps the code a bit cleaner. (and makes #6 above easier to implement)
发布评论

评论列表(0)

  1. 暂无评论