Andrew Dinsmore
Andrew Dinsmore

Reputation: 37

How to set a method inside one onClick method In ReactJS to finish execution after API call?

I need the background to change colors at the same time the api request is rendered.

I am building a Quote generator. Its a simple one button interface, that once clicked, loads a new quote and changes the background color. I could not find a good way to bind two methods to the same click event, so I have the API call and the color change taking place in the same method. The problem is, the color changes instantly, but the quote takes time to update. I tried calling component DidMount inside the method, but this did not work. I am sure there is an easier approach, I am just missing it. Here is my code

import React, { Component } from 'react'
import Button from './Button';
import axios from 'axios'
class QuoteBox extends Component{
   constructor(props){
         super(props)

     this.state = {
        quotes: [],
      colors: ["#16a085", "#27ae60",
             "#2c3e50", "#f39c12",
             "#e74c3c", "#9b59b6",
             "#FB6964", "#342224", 
             "#472E32", "#BDBB99",
             "#77B1A9", "#73A857"]
     }

   }
 componentDidMount(){
   axios.get('http://quotesondesign.com/wp-json/posts? 
   filter[orderby]=rand&filter[posts_per_page]3')
  .then(res=> this.setState({quotes: res.data[0]}))

}

getNext = (ev) =>{
  const {colors} = this.state
  const color = colors[Math.floor(Math.random()* colors.length)]
  var newQuote = Math.floor(Math.random() * 50)
  const API_URL = `http://quotesondesign.com/wp-json/posts? 
  filter[orderby]=rand&filter[posts_per_page]${newQuote}`
  ev.preventDefault()
  document.body.style.backgroundColor = color
  axios.get(API_URL)
  .then(res=> this.setState({quotes: res.data[0]}))
  document.body.style.backgroundColor = color
}

render(){
const {content,title} = this.state.quotes
const filteredContent = String(content).replace(/(<\w>)|(<\/\w>)| 
(&#\d{4})|(<\w* \/>)|(\/\w*)/gm, "").replace(/(;)/g,"'")
 console.log(content)

 return(
   <React.Fragment>
      <h2>A little inspiration for the day</h2>
      <div className='outerQuoteBox'>
        <div className='innerQuoteBox'>
            <p>{filteredContent}</p><br/><br/>{title}
        </div>
        <Button getNext={this.getNext} />
    </div>
    </React.Fragment>)
   }
 }


  export default QuoteBox

And this is my button component

 import React, { Component } from 'react'

 export class Button extends Component {
  render() {
    return (
        <button onClick={this.props.getNext} className='nextBtn' 
        type='button'>Next<button/>
    )
  }
}  

export default Button

I am going to have the font color change with the background as well,and I think I can figure that out, but the color changing so much sooner than the quote changing makes the whole thing look bad. It needs to happen all at once.

Upvotes: 0

Views: 87

Answers (1)

LMulvey
LMulvey

Reputation: 1680

You have two options with your current setup: you can change the background in a callback for your setState call, or, you can call it in the same function you're passing to your then clause from Axios.

Why? Axios returns a Promise which represents the eventual completion of an asynchronous request (i.e, API call). Your .then() call is fired upon a successful (non-error-throwing) completion of the request.

Your code otherwise keeps executing, hence, why your background was changing before your API call completed.

then()

getNext = (ev) =>{
  const {colors} = this.state
  const color = colors[Math.floor(Math.random()* colors.length)]
  var newQuote = Math.floor(Math.random() * 50)
  const API_URL = `http://quotesondesign.com/wp-json/posts? 
  filter[orderby]=rand&filter[posts_per_page]${newQuote}`
  ev.preventDefault()
  document.body.style.backgroundColor = color
  axios.get(API_URL)
  .then(res=> { 
     this.setState({quotes: res.data[0]});
     document.body.style.backgroundColor = color;
  });
}

setState callback

getNext = (ev) =>{
  const {colors} = this.state
  const color = colors[Math.floor(Math.random()* colors.length)]
  var newQuote = Math.floor(Math.random() * 50)
  const API_URL = `http://quotesondesign.com/wp-json/posts? 
  filter[orderby]=rand&filter[posts_per_page]${newQuote}`
  ev.preventDefault()
  document.body.style.backgroundColor = color
  axios.get(API_URL)
  .then(res=> { 
     this.setState({quotes: res.data[0]}, () => {
       document.body.style.backgroundColor = color;
     });
  });
}

Upvotes: 1

Related Questions