Search code examples
javascriptreactjsfrontendweb-deployment

How to show score value in React?


I am building a rock/paper/scissors React app, but I am having problems when I try to show the value of the score in my component. The app works fine, but I would like to increment the score of +1 if the user wins, decrement of -1 if the CPU wins, and updating the UI consequentially. I have problems finding a right way of passing the data through my components.

Could you please help me resolving this issue ?

Thanks a lot!

App.js

import React from "react"
import Header from "./components/Header"
import Main from "./components/Main"
import Footer from "./components/Footer"

import './App.css';

class App extends React.Component {
  constructor(){
    super()
    this.state = {
      score: 12
    }
    this.setScore = this.setScore.bind(this)
  }

  setScore() {
    this.setState((prevState) => {
      return {
        score: prevState.score + 1
      }
    })
  }

  render() {
    return (
      <div className="App">
        <div className="container">
          <Header 
              rock = "ROCK" 
              paper = "PAPER" 
              scissors = "SCISSORS" 
              score = {this.state.score} 
          />
          <Main setScore = {this.setScore}/>
          <Footer />
        </div>
      </div>
    )
  }
}

export default App;

Header.js

import React from 'react';
import Score from './Score';

import './Header.css';

function Header(props) {
  return (
    <div className="nav-container">
      <div className="title-container">
        <h1 className="no-margin">
          {props.rock} <br></br>
          {props.paper} <br></br>
          {props.scissors}
        </h1>
      </div>
      <div className="score-container">
        <Score />
      </div>
    </div>
  );
}

export default Header;

Score.js

import React from 'react';
import './Score.css';

class Score extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      score: 0,
    };
    this.handleChange = this.handleChange.bind(this);
  }

  handleChange() {
    this.setState((prevState) => {
      return {
        score: prevState.score + 1,
      };
    });
  }

  render() {
    return (
      <div>
        <div className="score-text">SCORE</div>
        <div className="score-value">{this.state.score}</div>
      </div>
    );
  }
}

export default Score;

Main.js

import React from "react"
import Choice from "./Choice"
import TryAgain from "./TryAgain"

import paper from '../images/icon-paper.svg'
import rock from '../images/icon-rock.svg'
import scissors from '../images/icon-scissors.svg'

import './Main.css';

class Main extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
            onScreen: true,
            choiceName: '',
            choiceImage: '',
            choiceBorderColor: '',
            choiceExtraBorderColor: '',
            houseChoice: '',
            results:'',
            score: 0,
            setScore: props.setScore
        }
        this.handleClick = this.handleClick.bind(this)
        this.handleTryAgainClick = this.handleTryAgainClick.bind(this)
    }

    /*function that handles the user choice*/
    handleClick = (choiceName, choiceImage, choiceBorderColor, choiceExtraBorderColor) => () => {
        this.setState({
            onScreen: false,
            choiceName,
            choiceImage,
            choiceBorderColor,
            choiceExtraBorderColor,
        })

        /*function that get a random number between 0 and 2, and set this number to the house index*/
        function getRandomInt(max) {
            return Math.floor(Math.random() * Math.floor(max));
        }

        const index = getRandomInt(3)

        this.setState({
            houseChoice: index
        })

        const results = this.getResults(choiceName, index).toUpperCase()
        this.setState({
            results: results,
        })

        if(results === "WIN") { /*what to put here*/
            const res = this.props.setScore
            console.log(res)
            return {
                res
            }
            console.log(this.state.score) 
            /*
            this.setState((prevState) => {
                return {
                    score: prevState.score + 1 
                }
            })*/
        } else if (results === "LOSE" && this.state.score > 0) {
            console.log(this.state.score)
            this.setState((prevState) => {
                return {
                    score: prevState.score - 1
                }
            })
        }
        else {
            console.log(this.state.score)
            this.setState((prevState) => {
                return {
                    score: prevState.score
                }
            })
        }
    }

    /*function that get the main logic and the results of the game*/
    getResults(choiceName, houseChoice) {
        if(choiceName === "paper" && houseChoice === 0) {
            return "draw"
        } else if(choiceName === "paper" && houseChoice === 1) {
            return "lose"
        } else if(choiceName === "paper" && houseChoice === 2) {
            return "win"
        }
        if(choiceName === "rock" && houseChoice === 0) {
            return "lose"
        } else if(choiceName === "rock" && houseChoice === 1) {
            return "win"
        } else if(choiceName === "rock" && houseChoice === 2) {
            return "draw"
        }
        if(choiceName === "scissors" && houseChoice === 0) {
            return "win"
        } else if(choiceName === "scissors" && houseChoice === 1) {
            return "draw"
        } else if(choiceName === "scissors" && houseChoice === 2) {
            return "lose"
        }
    }

    /*function that switches the screen and resets the index of the house*/
    handleTryAgainClick() {
        this.setState({
            onScreen: true,
            houseChoice: ''
        })
    }
    
    render() {
        return(
            <div>
                {/*HOME PAGE*/}
                <div className="main-container" style={{display: (this.state.onScreen ? "block" : "none")}}>
                    <div className="triangle-container">
                        <div onClick={this.handleClick}>
                            <Choice
                                name="paper"
                                image={paper} 
                                borderColor="hsl(230, 89%, 62%)" 
                                extraBorderColor="hsl(230, 89%, 65%)"
                                handleClick={this.handleClick}
                            />
                        </div>
                        <div onClick={this.handleClick}>
                            <Choice
                                name="scissors"
                                image={scissors} 
                                borderColor="hsl(39, 89%, 49%)" 
                                extraBorderColor="hsl(40, 84%, 53%)"
                                handleClick={this.handleClick}
                            />
                        </div>
                        <div style={{gridArea: "bottom"}} onClick={this.handleClick}>
                            <Choice 
                                name="rock"
                                image={rock} 
                                borderColor="hsl(349, 71%, 52%)" 
                                extraBorderColor="hsl(349, 70%, 56%)"
                                handleClick={this.handleClick}
                            />
                        </div>    
                    </div>
                </div>

                {/*RESULT PAGE*/}
                <div className="result-wrapper" style={{display: (!this.state.onScreen ? "grid" : "none")}}>

                    <div className="user-result-box">
                        <h4 className="result-title">YOU PICKED</h4>
                        <div 
                            className="elem-container result-container"
                            style={{
                                borderColor: this.state.choiceBorderColor, 
                                color: this.state.choiceExtraBorderColor
                            }}
                        >
                            <img src={this.state.choiceImage} className="choice-image" alt="img" />
                        </div>
                    </div>

                    <div className="house-result-box">
                        <h4 className="result-title">THE HOUSE PICKED</h4>

                        {this.state.houseChoice === 0 ? (

                            /*1*/
                            <div 
                                className="elem-container result-container"
                                style={{ 
                                    borderColor:"hsl(230, 89%, 62%)",
                                    color:"hsl(230, 89%, 65%)" 
                                }}
                            >
                                <img src={paper} className="choice-image" alt="img" />
                            </div>

                        ) : ( 

                            this.state.houseChoice === 1 ? (
                            
                            /*2*/
                            <div 
                                className="elem-container result-container"
                                style={{ 
                                    borderColor:"hsl(39, 89%, 49%)", 
                                    color:"hsl(40, 84%, 53%)" 
                                }}
                            >
                                <img src={scissors} className="choice-image" alt="img" />
                            </div>

                        ) : (

                            /*3*/
                            <div 
                                className="elem-container result-container"
                                    style={{ 
                                        borderColor:"hsl(349, 71%, 52%)", 
                                        color:"hsl(349, 70%, 56%)" 
                                    }}
                            >
                                <img src={rock} className="choice-image" alt="img" />
                            </div>
                        ))
                        }

                    </div>
                    <div className="final-result-container">
                    <h1 className="bold">YOU {this.state.results}</h1>
                        <TryAgain onClick={this.handleTryAgainClick}/>
                    </div>
                </div>
            </div>

        )
    }
}

export default Main

Solution

  • In your Main.js file, you're not calling the setScore function. You have to call it with ().

    if(results === "WIN") { 
        this.props.setScore()
        /* Remove this unnecessary code.
        console.log(res)
        return {
            res
        } */
    }
    

    When you call this.props.setScore(), it will invoke the function from the App.js and update the score for you. Then, App.js will pass the updated score automatically to the Score.js component as well.

    P.S: Please use online editors like codesandbox or codepen to demonstrate a working code. Otherwise, it will be tough to debug by scrolling the code.