Issues with React - Render Conditionally from Props

Issues with React - Render Conditionally from Props
0

#1

I am attempting to complete the ‘Render Conditionally from Props’ problem and am getting two test cases that continually fail. I’ve run the code and everything is working as stated by the problem. Any ideas?

class Results extends React.Component {
  constructor(props) {
    super(props);
  }
  render() {
    return (
      <h1>
      {
        this.props.fiftyFifty ? <p>You win!</p> : <p>You lose!</p>
      }
      </h1>
    )
  };
};

class GameOfChance extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      counter: 1
    }
    this.handleClick = this.handleClick.bind(this);
  }
  handleClick() {
    this.setState({
      counter: this.state.counter + 1
    });
  }
  render() {
    let expression = Math.random() > .5;
    return (
      <div>
        <button onClick={this.handleClick}>Play Again</button>
        { /* change code below this line */ }
        <Results fiftyFifty={expression}/>
        { /* change code above this line */ }
        <p>{'Turn: ' + this.state.counter}</p>
      </div>
    );
  }
};

Good - The GameOfChance component should exist and render to the page.

Good - GameOfChance should return a single button element.

Good - GameOfChance should return a single instance of the Results component, which has a prop called fiftyFifty.

Failing(But working in test window) - GameOfChance state should be initialized with a property of counter set to a value of 1.
When the GameOfChance component is first rendered to the DOM, a p element should be returned with the inner text of Turn: 1.

Good - When the GameOfChance component is first mounted to the DOM and each time the button is clicked thereafter, a single h1 element should be returned that randomly renders either You Win! or You Lose!.

Failing(But working in test window) - Each time the button is clicked, the counter state should be incremented by a value of 1, and a single p element should be rendered to the DOM that contains the text “Turn: N”, where N is the value of the counter state.


#2
      <h1>
      {
        this.props.fiftyFifty ? <p>You win!</p> : <p>You lose!</p>
      }
      </h1>

So, you are in JSX. JSX looks like HTML, but once you are inside curly braces, you are doing JavaScript. So, in your conditional statement, you don’t give it <p>You win!</p> (HTML), you want to give it JavaScipt, i.e., a string. The JSX will then pass it out to the HTML. To put it shortly, those should not be <p> tags but just a simple string.


#3

Kevin’s right. Plus, it’s kind of weird to render a <p> inside an <h1>. Also, Results looks like it can be turned into a functional component since it doesn’t handle any local state (it just get’s props from GameOfChance). Like this:

function Results(props) {
  return (
    <h1>
      { props.fiftyFifty ? 'You win!' : 'You lose!' }
    </h1>
  )
}

The rest looks good. Not sure why the test for the state of counter is not passing. Perhaps add a , Not really needed, but, the test suite might be expecting it:

  class GameOfChance extends React.Component {
    constructor(props) {
      super(props);
      this.state = {
        counter: 1,
      }
      this.handleClick = this.handleClick.bind(this);
    }

#4

True, that could be a functional component, but that was given by the tutorial so there is no need to change it.


#5

Ah, did not know that. Thanks for the clarification Kevin!


#6

I’m having a similar issue. The error i’m getting is: “When the GameOfChance component is first mounted to the DOM and each time the button is clicked thereafter, a single h1 element should be returned that randomly renders either You Win! or You Lose!.”

Does anyone know why and can explain it to me? Here is my code:

class Results extends React.Component {
  constructor(props) {
    super(props);
  }
  render() {
    return (
      <h1>
      {
      this.props.fiftyFifty ? "You win!" : "You lose!"
      }
      </h1>
    )
  };
};

class GameOfChance extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      counter: 1
    }
    this.handleClick = this.handleClick.bind(this);
  }
  handleClick() {
    this.setState({
      counter: this.state.counter + 1
    });
  }
  render() {
    let expression = Math.random()> 0.5;
    return (
      <div>
        <button onClick={this.handleClick}>Play Again</button>
        { /* change code below this line */ }
<Results fiftyFifty = {this.expression}/>

        { /* change code above this line */ }
        <p>{'Turn: ' + this.state.counter}</p>
      </div>
    );
  }
};

Thanks!


#7

I’ve edited your post for readability. When you enter a code block into the forum, precede it with a line of three backticks and follow it with a line of three backticks to make easier to read. See this post to find the backtick on your keyboard. The “preformatted text” tool in the editor (</>) will also add backticks around text.


#8

Your problem is here:

<Results fiftyFifty = {this.expression}/>

expression is a local variable to this method, there is no need to reference it with this - that would only be if it were a member of the class, afaik. If you get rid of this, it should work.


#9

I actually had an issue where the parser wasn’t loading and it wouldn’t let me advance. For some reason copying and pasting the code in works.


#10

any idea why
let expression = function() {return Math.random() > .5;}
didn’t work and
let expression = Math.random() > .5;
did?
with the former i kept getting either only true or only false if i kept clicking play again


#11

Because those are two different things. In the first case you are sending a function and in the second case you are sending a boolean. The component (as written) is expecting a boolean value.

This is easy to see. Go to the render method of your Results component and add the line:

    console.log('Results props', this.props.fiftyFifty, !!this.props.fiftyFifty)

as the first line of the render method. If you open up your browser console you can see what Results is getting. First it shows you what fiftyFifty is and then if it is “truthy” (the !! is a trick to turn any value to a boolean.) If you test the first method, you will see that the function always evaluates as “true” because a function is “truthy”. The key here is that the function never gets run. It just evaluates to true and the game always wins - it never looses.

Now, the app could have been designed differently. What if you want to send a function instead of the result of the function? Then you can call the function inside the Results component. If you change the jsx in Results to:

this.props.fiftyFifty() ? 'You win!' : 'You lose!'

Now you’ve received a function and you are invoking that function. This will pass the test. The difference is that the app is designed to evaluate to a boolean when expression is defined. Here we’ve changed it so we’re just creating a function, passing that to Results and evaluating the function there.

But as the problem is written, the component expects a boolean value so that is what we should send it, not a function that will give us a boolean if we run it.