I was following this tutorial on Linkedin-Learning and suddelny my code wouldn't work anymore. Unfortunately i don't really understand these error messages:
This warning always appears:
Warning: Failed prop type: The prop
onPress
is marked as required inRandomNumber
, but its value isundefined
.
And if I press one of the "buttons", this error messages comes up:
TypeError: _this.props.onPress is not a function. (In '_this.props.onPress(_this.props.id)', '_this.props.onPress' is undefined)
RandomNumber.js:
import React from "react";
import { Text, TouchableOpacity, StyleSheet } from "react-native";
import PropTypes from "prop-types";
class RandomNumber extends React.Component {
static propTypes = {
id: PropTypes.number.isRequired,
number: PropTypes.number.isRequired,
isDisabled: PropTypes.bool.isRequired,
onPress: PropTypes.func.isRequired,
};
handlePress = () => {
if (this.props.isDisabled) {
return;
}
this.props.onPress(this.props.id);
};
render() {
return (
<TouchableOpacity onPress={this.handlePress}>
<Text style={[styles.random, this.props.isDisabled && styles.disabled]}>
{this.props.number}
</Text>
</TouchableOpacity>
);
}
}
const styles = StyleSheet.create({
random: {
backgroundColor: "#999",
width: 120,
marginHorizontal: 15,
marginVertical: 25,
fontSize: 35,
textAlign: "center",
},
disabled: {
opacity: 0.2,
},
});
export default RandomNumber;
Game.js:
import React from "react";
import { View, Text, Button, StyleSheet } from "react-native";
import PropTypes from "prop-types";
import RandomNumber from "./RandomNumber";
import shuffle from "lodash.shuffle";
class Game extends React.Component {
static propTypes = {
randomNumberCount: PropTypes.number.isRequired,
initialSeconds: PropTypes.number.isRequired,
onPlayAgain: PropTypes.func.isRequired,
};
state = { selectedIds: [], remainingSeconds: this.props.initialSeconds };
gameStatus = "PLAYING";
randomNumbers = Array.from({ length: this.props.randomNumberCount }).map(
() => 1 + Math.floor(10 * Math.random())
);
target = this.randomNumbers
.slice(0, this.props.randomNumberCount - 2)
.reduce((acc, curr) => acc + curr, 0);
shuffledRandomNumbers = shuffle(this.randomNumbers);
componentDidMount() {
this.intervalID = setInterval(() => {
this.setState(
(prevState) => {
return { remainingSeconds: prevState.remainingSeconds - 1 };
},
() => {
if (this.state.remainingSeconds === 0) {
clearInterval(this.intervalID);
}
}
);
}, 1000);
}
componentWillUnmount() {
clearInterval(this.intervalID);
}
isNumberSelected = (numberIndex) => {
return this.state.selectedIds.indexOf(numberIndex) >= 0;
};
selectNumber = (numberIndex) => {
this.setState((prevState) => ({
selectedIds: [...prevState.selectedIds, numberIndex],
}));
};
UNSAFE_componentWillUpdate(nextProps, nextState) {
if (
nextState.selectedIds !== this.state.selectedIds ||
nextState.remainingSeconds === 0
) {
this.gameStatus = this.calcGameStatus(nextState);
if (this.gameStatus !== "PLAYING") {
clearInterval(this.intervalID);
}
}
}
calcGameStatus = (nextState) => {
const sumSelected = nextState.selectedIds.reduce((acc, curr) => {
return acc + this.shuffledRandomNumbers[curr];
}, 0);
if (this.state.remainingSeconds === 0) {
return "LOST";
}
if (sumSelected < this.target) {
return "PLAYING";
}
if (sumSelected === this.target) {
return "WON";
}
if (sumSelected > this.target) {
return "LOST";
}
};
render() {
const gameStatus = this.gameStatus;
return (
<View style={styles.container}>
<Text style={[styles.target, styles[`STATUS_${gameStatus}`]]}>
{this.target}
</Text>
<View style={styles.randomContainer}>
{this.shuffledRandomNumbers.map((randomNumber, index) => (
<RandomNumber
key={index}
id={index}
number={randomNumber}
onPress={this.state.selectNumber}
isDisabled={
this.isNumberSelected(index) || gameStatus !== "PLAYING"
}
/>
))}
</View>
{this.gameStatus !== "PLAYING" && (
<Button title="Play Again" onPress={this.props.onPlayAgain} />
)}
<Text>{this.state.remainingSeconds}</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
backgroundColor: "#ddd",
flex: 1,
},
target: {
fontSize: 40,
backgroundColor: "#bbb",
margin: 50,
textAlign: "center",
},
randomContainer: {
flex: 1,
flexDirection: "row",
flexWrap: "wrap",
justifyContent: "space-around",
},
STATUS_PLAYING: {
backgroundColor: "#bbb",
},
STATUS_WON: {
backgroundColor: "green",
},
STATUS_LOST: {
backgroundColor: "red",
},
});
export default Game;
App.js:
import React from "react";
import Game from "./Game";
class App extends React.Component {
state = { gameId: 1 };
resetGame = () => {
this.setState((prevState) => {
return { gameId: prevState.gameId + 1 };
});
};
render() {
return (
<Game
key={this.state.gameId}
onPlayAgain={this.resetGame}
randomNumberCount={6}
initialSeconds={10}
/>
);
}
}
export default App;
I've already tried some solutions from other posts, but none of them worked.
Any help is appreciated.