0

I'm using React to build a web application that will display a different quote every time the user clicks a button. I've been hunting for a way to get my component QuoteGenerator to re-render/refresh on a button-click, and I've tried all the possibilities presented in this article with no success.

class QuoteGenerator extends React.Component {
  constructor(props) {
        super(props);
        this.state = {num: Math.floor(Math.random() * quotes.length)};
    }

  render() {
    return(
      <div class="quoteBox">
        <div class="quote">
          "{quotes[this.state.num][0]}"<br/>
        </div>
        <button class="button btn" onClick={this.forceUpdate}>New Quote</button>
      </div>
    );
  }
}

Even creating a separate function that runs this.forceUpdate() or this.setState() and calling that function with onClick hasn't worked; I think I must be implementing something wrong. Does anyone see where my error might be?

Kiliann
  • 23
  • 2
  • 8

3 Answers3

3

Looks like you only pick the quote once. The constructor will run when the component is instantiated but will not run on every click.

Add a method:

nextQuote() {
  this.setState({
    num: Math.floor(Math.random() * quotes.length),
  });
}

and call it from your onClick (be careful with this).

Note: You don't normally need to call forceUpdate on a react component. Just call setState, tell React what changed and the update will happen on its own. From the docs:

Normally you should try to avoid all uses of forceUpdate() and only read from this.props and this.state in render().

Kos
  • 70,399
  • 25
  • 169
  • 233
  • To follow on, React components re-render when their state or props change. So if you want them to re-render in *reaction* to something, that something should logically be some kind of action that changes their state/props. For your example, if you change your `num` state value as Kos has shown, this will re-render your component with the new `num` value and produce the effect you desire – Jayce444 May 21 '18 at 08:54
1

You should use setState if you want to render the component instead of using this.forceUpdate().

You can refer ReactJS official documentation to verify the same because it is not good practice.

https://reactjs.org/docs/react-component.html#forceupdate

You can write custom method to setState every time you click the button. Also not sure where quotes value is coming from :)

Hopefully this is useful.

randomQuote = () => {
  this.setState({
    num: Math.floor(Math.random() * this.state.quotes.length)
  })
}
Kos
  • 70,399
  • 25
  • 169
  • 233
Johnson Samuel
  • 2,046
  • 2
  • 18
  • 29
0

Not sure onClick={this.forceUpdate} would have proper context to do its job. I'd wrap it in an inline function passing context (es6) or bind this context to it in the constructor

<button class="button btn" onClick={() => this.forceUpdate()}>New Quote</button>

Furthermore, global quotes object seems a bad pattern, you should give that to your component props

guillaumepotier
  • 7,369
  • 8
  • 45
  • 72