Skip to content Skip to sidebar Skip to footer

Toggle Background Color Of List On Click React.js

I am trying to create a list which has following features. On hover change background color of the listItem. On Click change background color of a listItem. Toggle background colo

Solution 1:

Before looking at any code, think about the actual cause of the problem. In your current implementation, each ListItem maintains its own click_flag state. When one ListItem is clicked, it sets its own click_flag to true, but this does not trigger the other ListItems to reset their own click_flag to false. This is the cause of the problem. The solution is to pass the click_flag as a props from the parent to each ListItem. It is the parent's responsibility to ensure that only ListItem gets prop as true, while the others are false. Likewise, it is the ListItem's responsibility to notify the parent when it has been clicked via a callback props passed down from the parent.

So, the ListItem looks like:

var ListItem = React.createClass({
    propTypes: {
        onClick: React.PropTypes.func.isRequired,
        isSelected: React.PropTypes.bool
    },
    getDefaultProps: function() {
        return {
            isSelected: false
        };
    },
    getInitialState: function() {
        return {
            hover_flag: false
        };
    },
    hoverEvent: function() {
        this.setState({hover_flag: !this.state.hover_flag});
    },
    render: function() {
        var liStyle = {
            background: '#cc181e'
        };
        if (this.props.isSelected || this.state.hover_flag) {
            liStyle['background'] = '#880000';
        }
        return (
            <li
                onClick={this.props.onClick}
                onMouseEnter={this.hoverEvent}
                onMouseLeave={this.hoverEvent}
                style={liStyle}>{this.props.name}
            </li>
        );
    }
});

And, the parent could look like this:

module.exports = React.createClass({
    getInitialState: function() {
        return {
            selectedItem: null
        };
    },
    clickHandler: function(idx) {
        this.setState({selectedItem: idx});
    },
    render: function() {
        var ulStyle = {
            padding: '0px',
            margin: '20px'
        };
        var items = this.props.data.map(function (item, idx) {
            var is_selected = this.state.selectedItem == idx;
            return <ListItem
                key={item.name}
                name={item.name}
                onClick={this.clickHandler.bind(this, idx)}
                isSelected={is_selected}
                />;
        }.bind(this));
        return (
            <ul style={ulStyle}>
                {items}
            </ul>
        );
    }
});

The parent maintains the state variable which stores which ListItem is the current selected one. It uses this state in render() to pass is_selected = true to only one ListItem, and all the others are passed false. The parent's state is updated by the clickHandler which is passed down as a props to each ListItem. See example fiddle here


Solution 2:

Since there will be only one selected item the parent component can maintain a state with the selected item index.

Parent Component

getInitialState: function(){
  return {selectedItem : null, items: this.props.data};
}

Change the render method to something like this (notice the isSelected property that is being sent to the ListItem component)

var selectedItem = this.state.selectedItem;
var list = this.state.items.map(function(data) {
  /*List of li elements */
  return <ListItem name={data.name} onSelect={this.onSelectHandler} isSelected={selectedItem === data.id} key={data.id}/> // <--- I would suggest having a unique ID
});

Lets implement onSelectHandler later.

ListItem

In the definition transfer the prop isSelected to ListItem's state

getInitialState: function(){
  return  {hover_flag: false, click_flag: this.props.isSelected} // <---- notice the change here
}

Now modify the clickEvent and trigger ListItem's onSelect property and send the clicked ListItem's name (i would suggest a unique ID here too)

clickEvent: function(){
  this.setState({click_flag: true});
  this.props.onSelect(this.props.name); // <--- I would suggest sending ID
}

Lets implement onSelectHandler for the parent component now

onSelectHandler: function(childItemID){
  this.setState({selectedItem: childItemID});
}

Hope this makes sense


Post a Comment for "Toggle Background Color Of List On Click React.js"