5

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. :)

3
  • 2
    I think, you want, onClick={() => this.baz()}? Commented Sep 25, 2018 at 16:11
  • @HoldOffHunger why use unnecessary IIFE? The idea is to pass function as value to property Commented Sep 25, 2018 at 16:18
  • @RafaelHovsepyan: It seems to work with that change. I posted an answer with a code sandbox where it works. Commented Sep 25, 2018 at 16:31

7 Answers 7

6

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

Sign up to request clarification or add additional context in comments.

Comments

2

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()}

1 Comment

Note that just passing {this.baz} won't give the proper scope to the function, and setting this.bar won't work, unless you bind scope to the function somehow (with an arrow function or with .bind)
1

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

Comments

0

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>

1 Comment

Or you can use arrow function and get rid of binds handleClick = () => { this.bar = 'baz'}
0

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>

Comments

0
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.

Comments

0

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>
        )
      }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.