this
this

Reputation: 351

React component not re-rendering with state update

I'm having some issues with a React component not updating, even though I can confirm that the state is being updated.

Link to Codepen is here: https://codepen.io/paalpwmd/full/WNveejG

  constructor(props){
    super(props)
    this.state = {
    }   
  }


  render(){
      return(
        <div>
          <a href="https://twitter.com/intent/tweet" id="tweet-quote">Tweet me</a>
        </div>
      )
    }
}

class QuoteBody extends React.Component{
  constructor(props){
    super(props)
    this.refreshQuote = this.refreshQuote.bind(this);
    this.state = { quote: "", author: "", quotePos: 0 };
  } 


refreshQuote() {
    let n = Math.floor(Math.random() * (120 - 0 + 1) + 0);
    this.setState({
    quotePos: n
    });
  console.log(this.state.quotePos)
  }

  render(){
    return(
      <div>
      <button id="new-quote" onClick={this.refreshQuote}>New Quote!</button>
      <div id="text"> 
      <p>{this.state.quote}</p>
        </div>
            <div id="author">
        <p>{"- " + this.state.author}</p>
        </div>
        <TwitterButton />
        </div>
    )
  }
componentDidMount() {
    fetch("https://gist.githubusercontent.com/camperbot/5a022b72e96c4c9585c32bf6a75f62d9/raw/e3c6895ce42069f0ee7e991229064f167fe8ccdc/quotes.json")
      .then(res => res.json())
      .then(
        (result) => {
          let i = this.state.quotePos;
          this.setState({
            quote: result.quotes[i].quote,
            author: result.quotes[i].author
          });
        },
        (error) => {
          this.setState({
            isLoaded: true,
            error
          });
        }
      )
  }
}

const QuoteBox = document.getElementById("quote-box")
ReactDOM.render(<QuoteBody />, QuoteBox);

I'm pretty new to React, so I'm not entirely sure what I'm doing wrong, so I'm sharing the whole project.

I'm expecting the QuoteBody component to update when refreshQuote is run, but it does not.

Upon some research, the best I could gather is that people have the same problem when doing things asynchronously, but I haven't found a clear solution that solves my exact problem (most of the help I've found is syntax errors, which I think I'm free of.

Thank you for your help in advance - I sincerely appreciate it!

Upvotes: 0

Views: 136

Answers (3)

this
this

Reputation: 351

Thank you so much! I made another fetch call in the refreshQuote body.

class TwitterButton extends React.Component{
constructor(props){
    super(props)
  }


  render(){
      return(
        <div>
          <a href="https://twitter.com/intent/tweet" id="tweet-quote">Tweet me</a>
        </div>
      )
    }
}

class QuoteBody extends React.Component{
  constructor(props){
    super(props)
    this.refreshQuote = this.refreshQuote.bind(this);
    this.state = { quote: "", author: "", quotePos: 0 };
  } 


refreshQuote() {
  fetch("https://gist.githubusercontent.com/camperbot/5a022b72e96c4c9585c32bf6a75f62d9/raw/e3c6895ce42069f0ee7e991229064f167fe8ccdc/quotes.json")
      .then(res => res.json())
      .then(
        (result) => {
          let i = this.state.quotePos;
          let n = Math.floor(Math.random() * (120 - 0 + 1) + 0);
          this.setState({
            quote: result.quotes[n].quote,
            author: result.quotes[n].author
          });
        },
        (error) => {
          this.setState({
            isLoaded: true,
            error
          });
        }
      )
  }


  render(){
    return(
      <div>
      <button id="new-quote" onClick={this.refreshQuote}>New Quote!</button>
      <div id="text"> 
      <p>{this.state.quote}</p>
        </div>
            <div id="author">
        <p>{"- " + this.state.author}</p>
        </div>
        <TwitterButton />
        </div>
    )
  }
componentDidMount() {
    fetch("https://gist.githubusercontent.com/camperbot/5a022b72e96c4c9585c32bf6a75f62d9/raw/e3c6895ce42069f0ee7e991229064f167fe8ccdc/quotes.json")
      .then(res => res.json())
      .then(
        (result) => {
          let n = Math.floor(Math.random() * (120 - 0 + 1) + 0);
          this.setState({
            quote: result.quotes[n].quote,
            author: result.quotes[n].author
          });
        },
        (error) => {
          this.setState({
            isLoaded: true,
            error
          });
        }
      )
  }
}

const QuoteBox = document.getElementById("quote-box")
ReactDOM.render(<QuoteBody />, QuoteBox);

Upvotes: 0

Akshay Bande
Akshay Bande

Reputation: 2587

You should call fetch and updating logic in the refreshQuote function. Cause that is what using this.setState function. componentDidMount will get called once your component is loaded the first time.

componentDidMount is like initializing components with the state. Then when the user will interact with component you can pass the events from child component to parent using function. In the above case, the function can be refreshQuote.

One more thing you are missing to bound this to component. Make refreshQuote arrow function.

You can define a custom function to which will update the state. Else add fetch logic to refreshQuote function.

Upvotes: 1

ivarni
ivarni

Reputation: 17878

The componentDidMount callback only runs when the component is mounted in the DOM, which is the first time you load the page in your case. Subsequent changes to state will not cause it to be mounted again. Since all you're changing is the quotePos part of the state the quote and author parts will not change, so the parts that use those won't be updated on the following render.

You'll probably want to keep the entire result-set from the fetch you do in componentDidMount in state and read the correct one using quotePos in your render.

Upvotes: 2

Related Questions