简体   繁体   中英

React Material UI ListItem Click

I want to create a country list that the ListItems in it are clickable and each ListItem has an icon near to text when clicked. I created a list and I implemented the clickable property of lists. But, when I click one list item in the list, I cannot select the other item in 1 click, it first deselects the previous one and then selects the other. This is the part of the code that my implementation is included:

class CountryList extends Component {
  constructor(props) {
    super(props);
    this.state = {clicked: false};
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    this.setState(state => ({
      clicked: !state.clicked
    }));
  }

  render() {
    const {classes} = this.props;
    const { clicked } = this.state;

    let listItems = myList.map((item) =>
      <>
        <ListItem className={ clicked ? classes.listItemClicked : classes.listItemNotClicked }
          onClick={this.handleClick} classes={classes.ListItem} button key={item.id}>
        
            {clicked ? 
            <ListItemIcon><DoneIcon style={{ color: 'rgb(239, 239, 239)', fontSize: '2.2rem' }}/></ListItemIcon>
           : <ListItemIcon><DoneIcon style={{ display: 'none', color: 'rgb(239, 239, 239)', fontSize: '2.2rem', backgroundColor: 'rgb(239, 239, 239)' }}/></ListItemIcon>}

           <ListItemText classes={{primary: classes.listItemText}} primary={item.value} />
       </ListItem>
       <Divider /> 
      </>
    );

    return (
      <List className={classes.list}>{listItems}</List>
    );
  }
}


const myList = [
  {id: 1, value: 'Albania'}, {id: 2, value: 'Austria'}, {id: 3, value: 'Belarus'}, {id: 4, value: 'Belgium'}, 
  {id: 5, value: 'Bosnia'}, {id: 6, value: 'Bulgaria'}, {id: 7, value: 'Croatia'}, {id: 8, value: 'Cyprus'}, 
  {id: 9, value: 'Czech'}, {id: 10, value: 'Denmark'}, {id: 11, value: 'Estonia'}, {id: 12, value: 'Finland'}, 
  {id: 13, value: 'France'}, {id: 14, value: 'Germany'}, {id: 15, value: 'Greece'}, {id: 16, value: 'Hungary'}, 
  {id: 17, value: 'Iceland'}, {id: 18, value: 'Ireland'}, {id: 19, value: 'Italy'}, {id: 20, value: 'Latvia'}, 
  {id: 21, value: 'Lithuania'}, {id: 22, value: 'Luxembourg'}, {id: 23, value: 'Macedonia'}, 
  {id: 24, value: 'Malta'}, {id: 25, value: 'Moldova'}, {id: 26, value: 'Montenegro'}, 
  {id: 27, value: 'Netherlands'}, {id: 28, value: 'Norway'}, {id: 29, value: 'Pakistan'}, 
  {id: 30, value: 'Poland'}, {id: 31, value: 'Portugal'}, {id: 32, value: 'Romania'}, {id: 33, value: 'Russia'}, 
  {id: 34, value: 'Serbia'}, {id: 35, value: 'Slovakia'}, {id: 36, value: 'Slovenia'}, 
  {id: 37, value: 'Spain'}, {id: 38, value: 'Sweden'}, {id: 39, value: 'Switzerland'}, {id: 40, value: 'Turkey'}, 
  {id: 41, value: 'Ukraine'}, {id: 42, value: 'Others'}
];

This is the code in App.js file:

<CountryList myList={myList} />

Also, I added an icon before the text. When I click 1 item, it shows the icon but, it also shows another element icon if my mouse is on it. I want to show the icon of the clicked element. How can I achieve this?

This is the screenshot:

在此处输入图片说明

If you look at carefully, there is an icon next to Belgium.

This is the link for the code in codesandbox:https://codesandbox.io/s/gifted-snow-5p1gd?file=/src/Country.js

Here is a working demo

You need to keep a active list item in a state, as i see in your code its this.state.clicked which is a boolean, so now you don't have a way to set the styles of clicked element because there is no reference to which is selected

set a state to keep the clicked item

this.state = { clickedItem: "" };

change onClick to.

<ListItem
    key={item.id}
    className={
      this.state.clickedItem === item.id
        ? classes.listItemClicked
        : classes.listItemNotClicked
    }
    onClick={() => this.handleClick(item)}
>

in onCLick set the clicked items to the state

handleClick(item) {
  this.setState({
    clickedItem: item.id
  });
}

Now you have the clicked item in the state, in the next render (which will be happen due to above state change) you can have the below logic in the render

<ListItem
  key={item.id}
  className={
    this.state.clickedItem === item.id //if item.id === clickedItemId then add a separate css class
      ? classes.listItemClicked
      : classes.listItemNotClicked
  }
  onClick={() => this.handleClick(item)}
>
  <ListItemIcon>
    //if item.id === clickedItemId then show the DoneIcon
    {this.state.clickedItem === item.id && (
      <DoneIcon
        style={{ color: "rgb(239, 239, 239)", fontSize: "2.2rem" }}
      />
    )}
  </ListItemIcon>
  <ListItemText primary={item.value} />
</ListItem>

You have to map clicked with index. Try this:

 class CountryList extends Component { constructor(props) { super(props); this.state = {clicked: null}; this.handleClick = this.handleClick.bind(this); } handleClick(key) { this.setState(state => ({ clicked: key })); } render() { const {classes} = this.props; const { clicked } = this.state; let listItems = myList.map((item, index) => <> <ListItem className={ clicked == index ? classes.listItemClicked : classes.listItemNotClicked } onClick={this.handleClick} classes={classes.ListItem} button key={item.id}> {clicked == index ? <ListItemIcon><DoneIcon style={{ color: 'rgb(239, 239, 239)', fontSize: '2.2rem' }}/></ListItemIcon> : <ListItemIcon><DoneIcon style={{ display: 'none', color: 'rgb(239, 239, 239)', fontSize: '2.2rem', backgroundColor: 'rgb(239, 239, 239)' }}/></ListItemIcon>} <ListItemText classes={{primary: classes.listItemText}} primary={item.value} /> </ListItem> <Divider /> </> ); return ( <List className={classes.list}>{listItems}</List> ); } } const myList = [ {id: 1, value: 'Albania'}, {id: 2, value: 'Austria'}, {id: 3, value: 'Belarus'}, {id: 4, value: 'Belgium'}, {id: 5, value: 'Bosnia'}, {id: 6, value: 'Bulgaria'}, {id: 7, value: 'Croatia'}, {id: 8, value: 'Cyprus'}, {id: 9, value: 'Czech'}, {id: 10, value: 'Denmark'}, {id: 11, value: 'Estonia'}, {id: 12, value: 'Finland'}, {id: 13, value: 'France'}, {id: 14, value: 'Germany'}, {id: 15, value: 'Greece'}, {id: 16, value: 'Hungary'}, {id: 17, value: 'Iceland'}, {id: 18, value: 'Ireland'}, {id: 19, value: 'Italy'}, {id: 20, value: 'Latvia'}, {id: 21, value: 'Lithuania'}, {id: 22, value: 'Luxembourg'}, {id: 23, value: 'Macedonia'}, {id: 24, value: 'Malta'}, {id: 25, value: 'Moldova'}, {id: 26, value: 'Montenegro'}, {id: 27, value: 'Netherlands'}, {id: 28, value: 'Norway'}, {id: 29, value: 'Pakistan'}, {id: 30, value: 'Poland'}, {id: 31, value: 'Portugal'}, {id: 32, value: 'Romania'}, {id: 33, value: 'Russia'}, {id: 34, value: 'Serbia'}, {id: 35, value: 'Slovakia'}, {id: 36, value: 'Slovenia'}, {id: 37, value: 'Spain'}, {id: 38, value: 'Sweden'}, {id: 39, value: 'Switzerland'}, {id: 40, value: 'Turkey'}, {id: 41, value: 'Ukraine'}, {id: 42, value: 'Others'} ];

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM