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 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
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 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. 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.
AutoComplete
component.Most of your React code here looks pretty good, but I've got some recommendations:
MovieList
function component that simply takes an array of movie
objects, and a titleFilter
string and renders them.componentDidMount
doesn't take arguments. searchTerm
should be a prop of FirstPageComponent
(presumably set by the parent component by some kind of selection or user input) AutoComplete
to TitleFilter
or the like. It's not really auto-completing, it's more of a filter field.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.<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. In this case, it wasn't that you couldn't find movies, it's that your filter is too restrictive.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 recommend each movie row component implement its own onClick
and call a function to set the filter.Small nits:
userInput: e.currentTarget.value,
could be shortened to userInput,
, which is shorthand for userInput: userInput,
(you already have a variable named userInput
.) 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.MovieRow
function component which takes a movie
object and renders it. It just keeps the code a bit cleaner. (and makes #6 above easier to implement)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.