Question

I have this ReactJS code to show a custom image button that toggles between 2 different images for ON and OFF state. Is there a simpler way to do this? I was hoping CSS might be less lines of code, but wasn't able to find a simple example.

The code below passes state up from <MyIconButton> to <MyPartyCatButton> then to <MyHomeView>. My app will have 4 of these custom buttons on the home screen, which is why I factored out <MyIconButton>.

btw - this is for a mobile App and I read (and noticed this myself) it's really slow using checkboxes on mobile browsers; that's why I chose to try this without using checkboxes.

ReactJS code

var MyIconButton = React.createClass({

  handleSubmit: function(e) {
    e.preventDefault();
    console.log("INSIDE: MyIconButton handleSubmit");

    // Change button's state ON/OFF, 
    // then sends state up the food chain via            
    //  this.props.updateFilter( b_buttonOn ).
    var b_buttonOn = false;
    if (this.props.pressed === true) {
      b_buttonOn = false;
    }
    else {
      b_buttonOn = true;
    }
    // updateFilter is a 'pointer' to a method in the calling React component.
    this.props.updateFilter( b_buttonOn ); 
  },

  render: function() {

    // Show On or Off image.
    // ** I could use ? : inside the JSX/HTML but prefer long form to make it explicitly obvious. 
    var buttonImg = "";
    if (this.props.pressed === true) {
      buttonImg = this.props.onpic;
    }
    else {
      buttonImg = this.props.offpic;
    }

    return (
      <div>
        <form onSubmit={this.handleSubmit}>
          <input type="image" src={buttonImg}></input>
        </form>
      </div>
    );
  }
});


// <MyPartyCatButton> Doesn't have it's own state, 
// passes state of <MyIconButton> 
// straight through to <MyHomeView>.
var MyPartyCatButton = React.createClass({

  render: function() {
    return (
      <MyIconButton pressed={this.props.pressed} updateFilter={this.props.updateFilter} onpic="static/images/icon1.jpeg" offpic="static/images/off-icon.jpg"/>
    );
  }
});

//
// Main App view
var MyHomeView = React.createClass({
  getInitialState: function() {
    // This is where I'll eventually get data from the server.
    return {
      b_MyPartyCat: true
    };
  },

  updatePartyCategory: function(value) {
    // Eventually will write value to the server.
    this.setState( {b_MyPartyCat: value} );
    console.log("INSIDE: MyHomeView() updatePartyCategory() " + this.state.b_MyPartyCat );
  },

  render: function() {
    return (
        <div>
         <MyPartyCatButton pressed={this.state.b_MyPartyCat} updateFilter={this.updatePartyCategory}/>
        </div>

        // Eventually will have 3 other categories i.e. Books, Skateboards, Trees !
    );
  }
});
Was it helpful?

Solution

if you update the coponent 'pressed' prop dynamically (like you did), simply

var MyIconButton= React.createClass({
    render: function(){
        var pic= this.props.pressed? this.props.onpic : this.props.offpic
        return <img 
            src={pic} 
            onClick={this.props.tuggleSelection}  //updateFilter is wierd name
        />
    }
})

(EDIT: this way, on MyPartyCatButton component, you can pass function to handle 'tuggleSelection' event. event function argument is an event object, but you have the button state allready in the wrapper state (the old one, so you should invert it). your code will be something like that:

render: function(){
    return <MyIconButton pressed={this.state.PartyCatPressed} tuggleSelection={this.updatePartyCategory} />
}
updatePartyCategory: function(e){
    this.setState( 
        {PartyCatPressed: !this.state.PartyCatPressed} //this invert PartyCatPressed value
    );
    console.log("INSIDE: MyHomeView() updatePartyCategory() " + this.state.b_MyPartyCat )
}

)

but if you don't, use prop for defult value:

var MyIconButton= React.createClass({
    getInitialState: function(){
        return {pressed: this.props.defultPressed}
    },
    handleClick: function(){
        this.setState({pressed: !this.state.pressed})
    },

    render: function(){
        var pic= this.state.pressed? this.props.onpic : this.props.offpic
        return <img 
            src={pic} 
            onClick={this.handleClick}
        />
    }
})
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top