1

I created a simple, 2 component app where the name of the animal shows the icon of the animal to generalize an issue I am having in a more complicated app.

Once a random animal is selected and merged into state, the Display component should re-render, and the animalIcon should also update, since stateis being pass down through props (or so I thought).

Instead, we are stuck on icon of whatever the first animal is (randomly chosen).

I would really like to know why the icon doesn't update, since I thought when state is changed, it will re-render the components that use that piece of information (in this case, the Display component), and console.log(animalIcon) is correctly showing me that on every re-render of the Display component, that the animalIcon is correctly being assigned the right element/icon.

The only thing not changing is the output of {animalIcon} in the return statement of the Display component.

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      currentAnimal: ''
    }
    this.getAnimal = this.getAnimal.bind(this);
  }
  
  getAnimal() {
    
    function getRandomAnimal(arr) {
      function getRandomIndex(min, max) {
        min = Math.ceil(min);
        max = Math.floor(max);
        return Math.floor(Math.random() * (max - min + 1)) + min;
      }
      
      return arr[getRandomIndex(0, arr.length - 1)];
    }
    
      const allAnimals = ['cat', 'dog', 'mouse'];
      const chosenAnimal = getRandomAnimal(allAnimals);
      this.setState({currentAnimal: chosenAnimal});
  }
  
  render() {
    return(
      <Display getAnimal={this.getAnimal} animal={this.state.currentAnimal}/>
    )
  }
}

function Display (props) {
  const icons = {
    cat: <i class="fas fa-cat"></i>,
    dog: <i class="fas fa-dog"></i>,
    mouse: <i class="fas fa-mouse-pointer"></i>,
  }
  
  let animalIcon = icons[props.animal.toLowerCase()];
  console.log(animalIcon);
  
  return (
    <div>
      <h1>{props.animal} looks like {animalIcon}</h1>
      <button onClick={props.getAnimal}>Get New Animal</button>
    </div>
  )
}

ReactDOM.render(<App />, document.querySelector('.root'));
<script src="https://use.fontawesome.com/releases/v5.5.0/js/all.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div class="root"></div>
WonkasWilly
  • 563
  • 1
  • 8
  • 21
  • 1
    Possible duplicate of [How can I get Font Awesome 5 to work with React?](https://stackoverflow.com/questions/47954237/how-can-i-get-font-awesome-5-to-work-with-react) – Agney Dec 05 '18 at 09:03
  • @BoyWithSilverWings I never would've thought that it would be Font Awesome that would be the issue. This is the actual solution I've been looking for. Thanks! – WonkasWilly Dec 06 '18 at 02:53

1 Answers1

4

You can wrap the animalIcon with attribute key , as you are passing props it seems its not updating correctly. This will tell react to update the icon if animal name is changed.

<span key={props.animal}>{
      animalIcon
    }</span>

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      currentAnimal: ''
    }
    this.getAnimal = this.getAnimal.bind(this);
  }

  getAnimal() {

    function getRandomAnimal(arr) {
      function getRandomIndex(min, max) {
        min = Math.ceil(min);
        max = Math.floor(max);
        return Math.floor(Math.random() * (max - min + 1)) + min;
      }

      return arr[getRandomIndex(0, arr.length - 1)];
    }

    const allAnimals = ['cat', 'dog', 'mouse'];
    const chosenAnimal = getRandomAnimal(allAnimals);
    this.setState({
      currentAnimal: chosenAnimal
    });
  }

  render() {
    return ( <
      Display getAnimal = {
        this.getAnimal
      }
      animal = {
        this.state.currentAnimal
      }
      />
    )
  }
}

function Display(props) {
  const icons = {
    cat: < i class = "fas fa-cat" > < /i>,
    dog: < i class = "fas fa-dog" > < /i>,
    mouse: < i class = "fas fa-mouse-pointer" > < /i>,
  }

  let animalIcon = icons[props.animal.toLowerCase()];
  console.log(props.animal);

  return ( <div ><h1> {
      props.animal
    }
    looks like <span key={props.animal}>{
      animalIcon
    }</span> < /h1> <
    button onClick = {
      props.getAnimal
    } > Get New Animal < /button> <
    /div>
  )
}

ReactDOM.render( < App / > , document.querySelector('.root'));
<script src="https://use.fontawesome.com/releases/v5.5.0/js/all.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div class="root"></div>
Just code
  • 13,553
  • 10
  • 51
  • 93