Trevor
Trevor

Reputation: 2467

React onclick event not responding

React newbie here.

Not sure why but these onclick events are not firing for me.

I'm importing this class into a main class so maybe my main class can't read the functions inside or something?

var React = require('react');
import { Button } from 'semantic-ui-react'

class TableDataRow extends React.Component {
    constructor(props) {
    super(props);
    this.state = {isToggleOn: true};

    // This binding is necessary to make `this` work in the callback
    this.handleClick = this.handleClick.bind(this);
  }

    handleClick() {
    this.setState(prevState => ({
      isToggleOn: !prevState.isToggleOn
    }));
  }

    render() {


        const item = this.props.item;

        var columns = Object.keys(item).map(function(key) {
          return <td value={key}>{item[key]}</td>
        });

        return (
            <tr>
                {columns}
                <td>
                    <button className="ui button edit blue" value="{item.id}">
                        <i className="edit icon"></i>
                    </button>
                </td>
                <td>
                    <button onClick={this.handleClick} className="ui button delete red" value="{item.id}">
                        <i className="delete icon"></i>
                        {this.state.isToggleOn ? 'ON' : 'OFF'}
                    </button>
                </td>
            </tr>
        );
    }
}
module.exports = TableDataRow;

Upvotes: 1

Views: 865

Answers (3)

Liren Yeo
Liren Yeo

Reputation: 3451

var React = require('react');
import { Button } from 'semantic-ui-react'

class TableDataRow extends React.Component {
  // you don't need constructor just for initial states
  state = {isToggleOn: true};

  // Use arrow function and get lexical binding
  handleClick = () => {
    this.setState({isToggleOn: !this.state.isToggleOn})
  }

  render() {
    // Do object destructuring, so from now on
    // item will be referred to this.props.item
    const {item} = this.props;
    const {isToggleOn} = this.state;

    return (
        <tr>
          { Object.keys(item).map(key => <td value={key}>{item[key]}</td>) }
          <td>
              <button className="ui button edit blue" value={item.id}>
                  <i className="edit icon"></i>
              </button>
          </td>
          <td>
            <button onClick={this.handleClick} className="ui button delete red" value={item.id}>
                <i className="delete icon"></i>
                {isToggleOn ? 'ON' : 'OFF'}
            </button>
          </td>
        </tr>
    );
  }
}
module.exports = TableDataRow;

Using arrow function creates lexical binding, which means it is always binded to where it was defined, that way you don't need to bind it in constructor - cleaner code.

This article explains all the different ways of handling 'this'

When you do var item = this.props.item, you're creating another copy of item. This can be achieved through destructuring: const {item} = this.props. Notice how I also destructured isToggleOn.

Simple intro to object destructuring

Lastly using .map and arrow function you can achieve some really clean code as shown above.

Upvotes: 1

miqueloi
miqueloi

Reputation: 698

You forgot to bind the handleClick to this:

<button onClick={this.handleClick.bind(this)} className="ui button delete red" value="{item.id}">
   <i className="delete icon"></i>
       {this.state.isToggleOn ? 'ON' : 'OFF'}
</button>

Upvotes: 0

Marco
Marco

Reputation: 527

Try using

this.setState(({prevState}) => ({
  isToggleOn: !prevState.isToggleOn
});

instead of

this.setState(prevState => ({
  isToggleOn: !prevState.isToggleOn
}));

Upvotes: 0

Related Questions