I'm having a problem with my searchbar component. When performing a search, the request is successful and we get the desired display, however if we want to do a new search over it we automatically return to the main menu during typing. Can you tell me how to keep the display of the previous search without returning? Thank you in advance
import React, {Component} from 'react'
import ReactDOM from 'react-dom'
import axios from 'axios'
class App extends Component {
constructor(props) {
super(props)
this.state = {
pokemon: '',
resultDatas : '',
search: false,
whiteList: [],
error:''
}
this.handleChange = this.handleChange.bind(this)
this.handleClick = this.handleClick.bind(this)
this.handleSubmit = this.handleSubmit.bind(this)
this.fillWhiteList()
}
//white list function to forbid all special characters
fillWhiteList() {
axios.get('https://pokeapi.co/api/v2/pokemon/')
.then(list => {
const resultList = list.data.results
const theList = resultList.map(theList => theList.name.toLowerCase())
this.setState({
whiteList: theList
})
})
}
//handle the value of the text field and keep letter in lower case
//deletion of white space in typing to not generate errors
//async to have the last letter of the value
handleChange = async function(e) {
await this.setState({
pokemon: e.target.value.toLowerCase().trim(),
resultDatas:''
})
}
//Call API function and data table recovery with 'resultDatas' state
handleSubmit = (e) => {
e.preventDefault()
axios.get('https://pokeapi.co/api/v2/pokemon/' + this.state.pokemon
)
.then( res => {
console.log(res);
const response = res.data
this.onResetField()
this.setState({
resultDatas: response,
search:true,
error: res.status
})
console.log(this.state.error);
})
}
//Home button function
handleClick() {
this.setState({
resultDatas : '',
search: false,
pokemon: ''
})
}
//clear input function when onClick in the cross icon
onResetField() {
const iconReset = document.querySelector('input')
iconReset.value = ''
}
render(){
// Home page display when no value is submitted
if (this.state.search === false || this.state.resultDatas === '') {
return (
<div>
<SearchBar
value={this.handleChange}
submit={this.handleSubmit}
placeholder="Search Pokemon"
/>
<Global
loading="Loading..."
/>
</div>
)
//Error display
}else if (!this.state.whiteList.includes(this.state.pokemon) || this.state.error !== 200) {
return(
<div>
<SearchBar
submit={this.handleSubmit}
value={this.handleChange}
placeholder="Search Pokemon"
/>
<Error
wrong="Pokemon not found please retry"
/>
<PreviousButton
previously={this.handleClick}
return="Back to menu"
/>
</div>
)
// pokemon display
}else {
return(
<div>
<SearchBar
submit={this.handleSubmit}
value={this.handleChange}
placeholder="Search Pokemon"
/>
<PreviousButton
previously={this.handleClick}
return="Back to menu"
/>
<ItemList
list={this.state.resultDatas}
/>
</div>
)
}
}
}
//homepage display
class Global extends Component {
constructor() {
super()
this.state = {
item:[],
isLoaded:false
}
}
//Api call for display home page
APICall() {
axios.get('https://pokeapi.co/api/v2/pokemon/venusaur')
.then(response => {
this.setState({
item: response,
isLoaded:true
})
})
}
render() {
// loading display if request not found
if (!this.state.isLoaded) {
return (
<div>
<div>{this.props.loading}</div>
</div>
)
}else {
return(
<div>
{this.state.item.name}
</div>
)
}
}
}
//Searchbar component
class SearchBar extends Component{
render(){
return(
<form onSubmit={this.props.submit} autoSave="off">
<input
inputMode="tel"
required="required"
autoComplete="off"
type="text"
onChange={this.props.value}
id="searchbar"
placeholder={this.props.placeholder}
/>
</form>
)
}
}
//list of Pokemon component
class ItemList extends Component{
render(){
return(
<div>
{this.props.list.name}
<img src={this.props.list.sprites.front_default} alt="pokemon"/>
</div>
)
}
}
// Previous button component
class PreviousButton extends Component{
render(){
return(
<button onClick={this.props.previously}>{this.props.return}</button>
)
}
}
//error page component
class Error extends Component{
render(){
return(
<div>
{this.props.wrong}
</div>
)
}
}
ReactDOM.render(<App/>, document.querySelector('#root'))
here a codesandbox in case it doesn't work https://codesandbox.io/s/keen-ritchie-t5kn8?file=/src/index.js
It looks like this is what is causing the issue.
//handle the value of the text field and keep letter in lower case
//deletion of white space in typing to not generate errors
//async to have the last letter of the value
handleChange = async function(e) {
await this.setState({
pokemon: e.target.value.toLowerCase().trim(),
resultDatas:''
})
}
When you handle your input value change, you are setting resultDatas
to an empty string. In your render function your "home page" is checking to see if search is equal to false or if your resultDatas is an empty string, so as soon as you start typing in a new search, it resets resultData and takes you to the home page.
if (this.state.search === false || this.state.resultDatas === '') {
return (
<div>
<SearchBar
value={this.handleChange}
submit={this.handleSubmit}
placeholder="Search Pokemon"
/>
<Global
loading="Loading..."
/>
</div>
)
}
To fix this, you could make it so typing doesn't automatically clear your resultDatas like so
handleChange = function(e) {
this.setState({
pokemon: e.target.value.toLowerCase().trim()
})
}
**I removed the async/await keywords from this function as this.setState is a callback, and not a promise.
CodeSandbox with changes: https://codesandbox.io/s/crazy-rgb-lwzne?file=/src/index.js
Additional Information
If you don't want to be immediately directed to your error page then you will need keep track of the current pokemon you have searched for separate from the current value that is being typed in. I've updated my CodeSandbox above to include these additional changes.
If you look at the CodeSandbox, you will see that there is now a currentPokemon
value in your state. Inside of the on submit function where you are setting state, I am then updating currentPokemon
to be equal to this.state.pokemon
. The final piece that pull this together is within the render function. You need to change your error page condition to check if your whitelist includes this.state.currentPokemon
instead of this.state.pokemon
.
You should use search
instead of resultDatas
to indicate search box status
handleChange = async function(e) {
await this.setState({
pokemon: e.target.value.toLowerCase().trim(),
search:false
})
}
then
render(){
// Home page display when no value is submitted
return (
<div>
<SearchBar
value={this.handleChange}
submit={this.handleSubmit}
placeholder="Search Pokemon"
/>
{!this.state.search && <Global
loading="Loading..."
/>}
{this.state.resultDatas && <ItemList
list={this.state.resultDatas}
/>}
.
.
.
</div>
)
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With