Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

setState not updating font awesome icon

I'm trying to dynamically render font awesome icon in myself written checkbox component. When I'm trying to update state of a with font awesome icon after clicking on it it is not updating. I've tried to move render to separate function and tried to use react-fontawesome but nothing helps. The state is updating but font awesome icons are the same svg code in html.

...
state = {
 checked: this.props.checked
}

toggleCheck = () => {
  this.setState({ checked: !this.state.checked });  
};

render () {

  const iconUnchecked = 'far fa-square';
  const iconChecked = 'fas fa-check-square';
  const iconClass = this.state.checked ? iconChecked : iconUnchecked;

  return (
    <span onClick={this.toggleCheck}>
      <i className={iconClass} />
    </span>
  );
}
like image 422
200OK Avatar asked Apr 18 '18 12:04

200OK


2 Answers

As I understood the font awesome js manipulates DOM and React manipulates virtual DOM. When font awesome js doing its own stuff React can't rerender it after state change. Im still on React 15 and maybe it's not the issue in React 16. I just found a solution for me to put every with font awesome in a div with unique key. This way React see that div must change because key was changed.

like image 97
200OK Avatar answered Sep 18 '22 14:09

200OK


Try that one https://jsfiddle.net/n5u2wwjg/30533/

For me seems to work

Check exactly jsfiddle it works, but not a snippet. Snippet is just to satisfy editor.

class TodoApp extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      checked: this.props.checked
    }
    this.toggleCheck = this.toggleCheck.bind(this);
  }
  
  toggleCheck() {
    this.setState({ checked: !this.state.checked });  
  }
  
  render() {
    const iconUnchecked = 'far fa-square';
  	const iconChecked = 'fas fa-check-square';
  	let iconClass = this.state.checked ? iconChecked : iconUnchecked;

    return (
      <span onClick={this.toggleCheck}>
        <i className={iconClass} />
      </span>
    )
  }
}

ReactDOM.render(<TodoApp />, document.querySelector("#app"))
body {
  background: #20262E;
  padding: 20px;
  font-family: Helvetica;
}

#app {
  background: #fff;
  border-radius: 4px;
  padding: 20px;
  transition: all 0.2s;
}

li {
  margin: 8px 0;
}

h2 {
  font-weight: bold;
  margin-bottom: 15px;
}

.done {
  color: rgba(0, 0, 0, 0.3);
  text-decoration: line-through;
}

input {
  margin-right: 5px;
}
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.10/css/all.css" integrity="sha384-+d0P83n9kaQMCwj8F4RJB66tzIwOKmrdb46+porD/OvrJ+37WqIM7UoBtwHO6Nlg" crossorigin="anonymous">

<div id="app"></div>
like image 38
Sergey Avatar answered Sep 18 '22 14:09

Sergey