Reputation: 100
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
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
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
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