Conditionally rendering Font Awesome Icons in React

I am currently mapping an array to produce several Font Awesome Icons. I have an OnClick method which I am using as a flag: I want to change the icon of only the clicked item. This is my implementation:

<FontAwesomeIcon id={i.key}  onClick={this.ToggleIcon}  icon={this.state.clicked ? faHeart : faCalendarAlt}/> 

ToggleIcon = (e) =>{
if((this.state.clicked)){
    this.setState({clicked: true})
  }


 else if!(this.state.clicked)){
   this.setState({clicked: false})
  }
}

However, this changes ALL of the icons instead of only the clicked one. How can I accomplish this?

It’s hard to tell what’s wrong from what you pasted. Do you have a link to your source or codepen you could share?

Welcome to this community;

This could be your problem, there is not opening parenthesis for that extra closing one.
else if !(this.state.click))

change it to ->
else if (!(this.state.click))

It’s hard to be certain as you haven’t pasted all your code but it looks like you have one state variable called clicked that is stored in the parent component and shared by all the FontAwesomeIcon components. So whenever you click on one icon it sets the single state variable and that changes all your icons.**

There are two solutions to this problem, the simple and less useful fix is to store each icon’s state locally like so

class IconWrapper extends React.Component {
  state = { clicked: false };
  toggleIcon = () => {
    setState(state => ({ clicked: !state.clicked }));
  }

  render = () => <FontAwesomeIcon id={this.props.key}  onClick={this.toggleIcon} icon={this.state.clicked ? faHeart : faCalendarAlt} />
}

// the you can use the icon like so
icons.map(icon => <IconWrapper key={icon.key} />);

The problem with the code above is that the parent component doesn’t know which icons have been clicked (and you can’t pass state up). This might not be an issue while you’re learning but in a production app in would be a dealbreaker. The solution is to store an array or object in the parent state that records which buttons have been toggled, the specifics of how you would do that would depend on what you were trying to achieve. But a starting point would be to store an object keyed by icon id in the parent’s state like this:

const icons = [
  { id: 0, name: 'whatever' },
  { id: 1, name: 'whatever2' },
  ...
];
class IconList extends React.Component {
  state = {}
  toggleIcon = id => {
    this.setState(state => ({ [id]: !state[id] }));
  }

  render = () => (
    <div>
      {icons.map(icon => (
        <FontAwesomeIcon
          id={icon.id}
          onClick={() => this.toggleIcon(icon.id)}
          icon={this.state[icon.id] ? faHeart : faCalendarAlt }/>)
        )}
    </div>
  )
}

Good luck and I hope that wasn’t too much info.

** There are other more complicated causes of accidental shared state, but you’ll need to post more code if the suggestion here doesn’t solve your problem.

PS Tip: When toggling a value in state it’s good practice to use a function like I did above so that you won’t get rare but tricky bugs when react batches state updates. Don’t worry about it too much yet, but I thought I’d explain why I did it that way.