pfincent
pfincent

Reputation: 485

onClick method of React Button using JSX

I started learning the basics of JS and wrote a small example to examine how buttons work in React using JSX, but I find it to be a bit confusing.

I first create a React component and initialize a variable called bar with value 'bar' in the constructor.

I'd like to have this value change to 'baz' when a button is pressed.

My code looks like this:

<div id="root"></div>
<script type="text/babel">

    class Foo extends React.Component {
      constructor(props) {
        super(props);
        this.bar = 'bar'
      }

      baz(){
        this.bar = 'baz'
      }

      render() {
        return (
          <div>
            <button onClick={this.baz()}>baz</button>
            <p>{this.bar}</p>
          </div>
        );
      }
    }

    ReactDOM.render(
      <Foo />,
      document.getElementById('root')
    );

</script>

Contrary to my expectations, the value 'baz' is shown right away when I load the page containing this code in my browser.

I'm sorry for asking a probably very newbie question, but I don't understand why 'baz' is shown right away, instead of only after I pressed the button. Thank you for your time. :)

Upvotes: 4

Views: 12444

Answers (7)

adam.k
adam.k

Reputation: 632

You need to store your values in state, and then bind you click handler to the component. Then use setState() to change the value of state. When state changes, your component will re-render:

class Foo extends React.Component {
      constructor () {
        super()
        this.state = {
          bar: 'bar'
        }
        this.handleClick = this.handleClick.bind(this)
      }
      handleClick () {
        this.setState({
          bar: 'baz'
        })
      }
      render () {
        return (
          <div>
            <button onClick={this.handleClick}>baz</button>
            <p>{this.state.bar}</p>
          </div>
        )
      }
}

Upvotes: 0

Mo7
Mo7

Reputation: 129

import React, { Component } from "react";

class Bar extends Component {
  constructor(props) {
    super(props);
    this.state = {
      bar: "bar"
    };
  }

  handleClick = () => {
    this.setState({ bar: "baz" });
  };

  render() {
    const value = this.state.bar;
    return (
      <div>
        <button onClick={this.handleClick}>baz</button>
        <p>{value}</p>
      </div>
    );
  }
}

A couple of things :

  • Set state in the constructor.
  • Use arrow functions (instead of binding in the constructor ... cleaner).
  • Use const when assigning a value that won't change in the function.

Upvotes: 0

Steve Archer
Steve Archer

Reputation: 641

You're calling the baz function during the render, that's why the change happens immediately:

<button onClick={this.baz()}>baz</button>

If you pass a function instead of calling a function, the function will get called when the button is pressed instead:

<button onClick={() => this.baz()}>baz</button>

Upvotes: 0

ashish singh
ashish singh

Reputation: 6914

You can try this:

class Foo extends React.Component {
  constructor(props) {
    super(props);
    this.state = { text: "bar" };
  }

  baz() {
    this.setState({ text: "baz" });
  }

  render() {
    return (
      <div>
        <button onClick={() => this.baz()}>baz</button>
        <p>{this.state.text}</p>
      </div>
    );
  }
}

ReactDOM.render(<Foo />, document.getElementById("root"));

The thing is to update the screen (DOM) its better to change state to let the component re-render. And for the problem that value was initially changed , other answers explain them well

Upvotes: 6

HoldOffHunger
HoldOffHunger

Reputation: 20911

I pointed out the solution in a comment above, so, I'll thresh out that comment a bit more...

You have...

<button onClick={this.baz()}>baz</button>

You want...

<button onClick={() => this.baz()}>baz</button>

I have also threshed out the rest of your code to produce the result you wanted ("I'd like to have this value change to 'baz' when a button is pressed."). You also needed...

this.setState(this);

See a full working example here:

https://codesandbox.io/s/vj904qy4o0

Upvotes: 1

Shubham Gupta
Shubham Gupta

Reputation: 2646

The way you are trying to use function is incorrect. Refer to one of the below two methods. Also, bind your function to this context in the constructor.

this.baz = this.baz.bind(this);

Then

onClick={this.baz}

OR

onClick={() => this.baz()}

Upvotes: 2

White Elephant
White Elephant

Reputation: 1381

The reason baz is shown right away is because you're calling the function in the click binding. You should also bind your click handler to your React class. Here's an example of how this should look:

<div id="root"></div>
<script type="text/babel">

    class Foo extends React.Component {
      constructor(props) {
        super(props);
        this.bar = 'bar';
        this.handleClick = this.handleClick.bind(this);
      }

      handleClick() {
        this.bar = 'baz';
      }

      render() {
        return (
          <div>
            <button onClick={this.handleClick}>baz</button>
            <p>{this.bar}</p>
          </div>
        );
      }
    }

    ReactDOM.render(
      <Foo />,
      document.getElementById('root')
    );

</script>

Upvotes: 0

Related Questions