Lygis
Lygis

Reputation: 100

React: How to update fetch with new query

I was trying to change query so what i am fetching would update, but it only updates i put there for testing. I would really appreciate help. And is it better to use this class method or learn using hooks? Since when i was googling i found something of a solution, but it was using hooks.

    class App extends Component {
  constructor() {
    super();
    this.state = {
      search: '',
      photos: [],
      query: 'space'
    }
    this.handleClick = this.handleClick.bind(this)
  }
  async componentDidMount() {
    
    const {query} = this.state
  try{
    const responseSearch = await client.photos.search({query, per_page: 20 });
    const dataSearch = await responseSearch.photos;
    console.log(responseSearch)
    this.setState({photos: dataSearch})
    if (responseSearch.ok) {
      throw Error(responseSearch.statusText);
    }
  }catch (error) {
    console.log(error);
  }
  }
  handleClick(){
    this.setState({query: 'nature'})
  }
 

render() {
  const {photos, search, query} = this.state;
  const filteredImages = photos.filter( card =>
     card.photographer.toLowerCase().includes(search.toLowerCase() )
  ) 
  
      return (
      <div className="App">
      <Particles className ='particles'
       params={particlesOptions}
       />
       <h2>{query}</h2>
       <button onClick={this.handleClick}>change</button>
       <Nav 
       categories={categories} 
       />
      <SearchBox  
          placeholder='search cards'
          handleChange={e => this.setState({query: e.target.value})}
        />
        <CardGroup cards={filteredImages} />
      </div>
     );  
}
}

Upvotes: 4

Views: 532

Answers (3)

usafder
usafder

Reputation: 816

You can use another lifecycle method called componentDidUpdate which will get invoked whenever a props or state is changed (note that this does not get called initially when the component is rendered so you will still have to use componentDidMount).

And then you can shift your API call in a separate method (let's call it fetchData) and reuse it in both componentDidMount as well as componentDidUpdate so your code will look something like below:

fetchData = async () => {
  try {
    const responseSearch = await client.photos.search({ query, per_page: 20 });
    const dataSearch = await responseSearch.photos;
    console.log(responseSearch)
    this.setState({ photos: dataSearch })
    if (responseSearch.ok) {
      throw Error(responseSearch.statusText);
    }
  } catch (error) {
    console.log(error);
  }
}

componentDidMount() {
  this.fetchData();
}

componentDidUpdate(prevProps, prevState) {
  // have a condition to avoid infinite fetchData calls
  if (prevState.query !== this.state.query) {
    this.fetchData();
  }
}

Upvotes: 1

Ali Faris
Ali Faris

Reputation: 18592

I would create a method that fetches the data fetchData, then I would call that method in componentDidMount and I would create another method to handle query changes and call fetchData after the state updated

componentDidMount() {
    this.fetchData();
}

fetchData = () => {
      ... //fetch code
}

changeQuery = (query) => { 
    this.setState({query : query} , this.fetchData);
}

render() { 
   ...
   <SearchBox  
      placeholder='search cards'
      handleChange={e => this.changeQuery(e.target.value)}
    />

   ...
} 

you want to disable the input while the fetching happening

Upvotes: 0

cangokceaslan
cangokceaslan

Reputation: 482

Fetching will not update if you put it into the lifecycle method componentDidMount. It is not okay to put the fetch into render. You better trigger a fetch method after setState is done.

handleClick(){
   this.setState({query: 'nature'},this.fetchAgain)
}
fetchAgain(){
   const {query} = this.state
   try{
       const responseSearch = await client.photos.search({query, per_page: 20 });
       const dataSearch = await responseSearch.photos;
       console.log(responseSearch)
       this.setState({photos: dataSearch})
       if (responseSearch.ok) {
           throw Error(responseSearch.statusText);
        }
       }catch (error) {
            console.log(error);
       }
}

Upvotes: 0

Related Questions