How to switch MaterialUI icon when clicked

Viewed 7705

In a list, each list item has an "AddIcon". When clicked I would like to switch that icon to a "BlockIcon" according to it's "id"

import React from 'react'
import {List, ListItem} from '@material-ui/core'
import AddCircleIcon from '@material-ui/icons/AddCircleOutline'
import BlockIcon from '@material-ui/icons/BlockOutlined'

const StackOverflow = () => {
    const handleIconClick = (id) => {
        // change <AddCircleIcon /> to <BlockIcon /> at "id"
    }
    return (
        <List component="nav">
            <ListItem>
                <ListItem button onClick={handleIconClick(101)}>
                    <AddCircleIcon /> 
                </ListItem>
            </ListItem>
        </List>
    )
}

export default StackOverflow

When icon is clicked, I expect the AddIcon to change to a BlockIcon.

5 Answers

You should create a state variable to hold the status of clickec or not clicked you that you can use it to swap the icon

import React from 'react'
import {List, ListItem} from '@material-ui/core'
import AddCircleIcon from '@material-ui/icons/AddCircleOutline'
import BlockIcon from '@material-ui/icons/BlockOutlined'

const StackOverflow = () => {
    const [clicked, setClicked] = useState(false)
    const handleIconClick = (id) => {
         setClicked(true)
        // change <AddCircleIcon /> to <BlockIcon /> at "id"
    }
    return (
        <List component="nav">
            <ListItem>
                <ListItem button onClick={handleIconClick(101)}>
                    {clicked ? <BlockIcon /> : <AddCircleIcon /> }
                </ListItem>
            </ListItem>
        </List>
    )
}

export default StackOverflow

I am also noticing that since you are using a list you will want to maybe click on multiple items and if that is the case then you should rather have it of the form below

const StackOverflow = () => {
    const [clicks, setClicks] = useState([])
     //add the id to the array of clicked items if it doesn't exist but if it does exist remove it. this makes sure that double clicking on an item brings it back to normal
    const handleIconClick = (id) => {
         let result =  clicks.includes(id)? clicks.filter(click => click != id): [...clicks, id]
         setClicks(result)
        // change <AddCircleIcon /> to <BlockIcon /> at "id"
    }
    return (
        <List component="nav">
            <ListItem>
                <ListItem button onClick={handleIconClick(101)}>
                    {clicks.includes(101) ? <BlockIcon /> : <AddCircleIcon /> }
                </ListItem>
            </ListItem>
        </List>
    )
}

export default StackOverflow

In the return statement, Note that if you are looping through the items before displaying then you will have to sent but the id in the clicks.include(id) and handleIconClick(id) will now be using the id not the hard coded number

Added a working example(https://codesandbox.io/s/keen-kowalevski-cguvs?fontsize=14)

import React, { useState } from "react";
import ReactDOM from "react-dom";
import IconButton from "@material-ui/core/IconButton";
import AddCircleIcon from "@material-ui/icons/AddCircleOutline";
import BlockIcon from "@material-ui/icons/BlockOutlined";

function App() {
  const [clicked, setClicked] = useState();

  return (
    <IconButton onClick={() => setClicked(true)}>
      {clicked ? <BlockIcon /> : <AddCircleIcon />}
    </IconButton>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Save the icon id in the component state, and render the icon conditionally:

import React, { useState } from "react";
import { List, ListItem } from "@material-ui/core";
import AddCircleIcon from "@material-ui/icons/AddCircleOutline";
import BlockIcon from "@material-ui/icons/BlockOutlined";

const StackOverflow = (props) => {
  const [iconId, setIconId] = useState(100);

  const handleIconClick = (id) => () => {
    setIconId(id);
  };

  return (
    <List component="nav">
      <ListItem>
        <ListItem button onClick={handleIconClick(101)}>
          {iconId === 100 ?  <AddCircleIcon /> : <BlockIcon />}
        </ListItem>
      </ListItem>
    </List>
  );
};

export default StackOverflow;
import "./App.css";
import ThumbUpAltIcon from "@material-ui/icons/ThumbUpAlt";
import React, { useState } from "react";

function App() {
const [likeColor, setLikeColor] = useState("");
const handleLike = () => {
    const color = likeColor ? "" : "primary";
    setLikeColor(color);
   };
return (
   <div className="App">
       <ThumbUpAltIcon onClick={handleLike} color={likeColor}></ThumbUpAltIcon>
   </div>
       );
   }    

export default App;

The below example work as we expected way with the button

import React, { useState } from "react";
import ReactDOM from "react-dom";
import Button from "@material-ui/core/Button";
import Add from "@material-ui/icons/Add";
import Remove from "@material-ui/icons/Remove";

import "./styles.css";

function App() {
  const [clicked, setClicked] = useState(true);

  return (
    <Button variant="contained" onClick={() => setClicked(!clicked)}>
      Column {clicked ? <Add color="primary"/> : <Remove color="secondary"/>}
    </Button>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Related