【发布时间】:2021-10-07 14:09:47
【问题描述】:
我正在尝试将一个类组件重构为功能组件,但是当我单击其中一个骰子或滚动按钮时,我收到错误“TypeError: Cannot read properties of undefined (reading 'slice')”。
我将类组件Game.js重构为功能组件Game.js时出现的错误,不知道如何解决。如果有人可以向我解释,错误在哪里......
错误:
类组件 Game.js
import React from 'react';
import '../css/Game.css';
import Dice from './Dice';
import ScoreCard from './ScoreCard';
import { rollD, scoringFunctions } from '../helpers.js';
class Game extends React.Component {
constructor(props) {
super(props);
this.state = {
rollsLeft: 2,
dice: Array.from(Array(5)).map(i => ({value: rollD(), locked: false})),
score: 0,
upperBonus: false,
yahtzeeBonus: 0,
yahtzeeMode: false,
scoreItems: [
{name: 'Ones', score: null, description: 'Sum of all Ones'},
{name: 'Twos', score: null, description: 'Sum of all Twos'},
{name: 'Threes', score: null, description: 'Sum of all Threes'},
{name: 'Fours', score: null, description: 'Sum of all Fours'},
{name: 'Fives', score: null, description: 'Sum of all Fives'},
{name: 'Sixes', score: null, description: 'Sum of all Sixes'},
{name: '3 of a kind', score: null, description: 'Sum of all dice if 3 are the same'},
{name: '4 of a kind', score: null, description: 'Sum of all dice if 4 are the same'},
{name: 'Small Straight', score: null, description: '30 points for a small straight'},
{name: 'Large Straight', score: null, description: '40 points for a large straight'},
{name: 'Full House', score: null, description: '25 points for a full house'},
{name: 'YAHTZEE', score: null, description: '50 points for yahtzee'},
{name: 'Chance', score: null, description: 'Sum all dice'}
]
}
this.rollDice = this.rollDice.bind(this);
this.resetRoll = this.resetRoll.bind(this);
this.toggleDieLock = this.toggleDieLock.bind(this);
this.handleScore = this.handleScore.bind(this);
this.updateBonus = this.updateBonus.bind(this);
this.checkUpperBonus = this.checkUpperBonus.bind(this);
this.updateYahtzeeState = this.updateYahtzeeState.bind(this);
this.isYahtzee = this.isYahtzee.bind(this);
}
rollDice() {
const newDice = this.state.dice.map((die) => {
return die.locked ? die : {...die, value: rollD()};
})
this.setState(prev => (
{
rollsLeft: prev.rollsLeft - 1,
dice: newDice
}), () => this.isYahtzee());
}
resetRoll() {
this.setState(
{
dice: Array.from(Array(5)).map(i => ({value: rollD(), locked: false})),
rollsLeft: 2
}, () => this.isYahtzee()
)
}
toggleDieLock(index) {
this.setState((prev) => {
return({
dice: prev.dice.map((die, i) => {
if(i === index) {
return {...die, locked: !die.locked};
} else {
return die
}
})
})
})
}
isYahtzee() {
let yahtzeeDice;
for(let i = 0; i < this.state.dice.length - 1; i++) {
if (this.state.dice[i].value !== this.state.dice[i + 1].value) {
return this.setState({yahtzeeMode: false})
}
}
if(this.state.yahtzeeBonus) this.setState({yahtzeeMode: true})
}
handleScore(name) {
let scoreValue = scoringFunctions[name](this.state.dice, this.state.yahtzeeMode);
let index;
let yahtzeeIndex;
for(let i = 0; i < this.state.scoreItems.length; i++) {
if(this.state.scoreItems[i].name === name) {
index = i;
}
if(this.state.scoreItems[i].name === 'YAHTZEE') {
yahtzeeIndex = i;
}
}
let updatedScoreItems = [...this.state.scoreItems];
updatedScoreItems[index].score = scoreValue;
this.setState((prev) => (
{
score: prev.score + scoreValue,
scoreItems: updatedScoreItems
}
), () => {this.updateBonus(yahtzeeIndex)})
this.resetRoll();
}
updateBonus(yahtzeeIndex) {
if(!this.state.upperBonus) this.checkUpperBonus();
if(!this.state.yahtzeeBonus) {
this.updateYahtzeeState(yahtzeeIndex);
} else if(this.state.yahtzeeMode) {
this.setState((prev) => (
{
score: prev.score + 100,
yahtzeeBonus: prev.yahtzeeBonus + 1
}))
}
}
checkUpperBonus() {
const totalUpper = this.state.scoreItems.slice(0, 6).reduce((total, item) => {
return item.score ? item.score + total : 0 + total;
}, 0);
if(totalUpper >= 63) {
this.setState((prev) => (
{
upperBonus: true,
score: prev.score + 35
}
))
}
}
updateYahtzeeState(yahtzeeIndex) {
if(this.state.scoreItems[yahtzeeIndex].score) {
this.setState((prev) => ({yahtzeeBonus: prev.yahtzeeBonus + 1}))
}
}
render() {
return (
<div className="game">
<div className="header">
<div className="title">
<h1 className="h1">Yahtzee!</h1>
</div>
<Dice
dice={this.state.dice}
rollsLeft={this.state.rollsLeft}
rollDice={this.rollDice}
toggleDieLock={this.toggleDieLock}
yahtzeeMode={this.state.yahtzeeMode}
/>
</div>
<ScoreCard
dice={this.state.dice}
upperBonus={this.state.upperBonus}
yahtzeeBonus={this.state.yahtzeeBonus}
resetRoll={this.resetRoll}
handleScore={this.handleScore}
scoreItems={this.state.scoreItems}
/>
<div className="score-header">
<h2 className="score">{`Total Score: ${this.state.score}`}</h2>
</div>
</div>
)
}
}
export default Game;
功能组件 Game.js
import React, { useState } from 'react';
import '../css/Game.css';
import Dice from './Dice';
import ScoreCard from './ScoreCard';
import { rollD, scoringFunctions } from '../helpers.js';
function Game() {
const [gameState, setGameState] = useState({
rollsLeft: 2,
dice: Array.from(Array(5)).map(i => ({value: rollD(), locked: false})),
score: 0,
upperBonus: false,
yahtzeeBonus: 0,
yahtzeeMode: false,
scoreItems: [
{name: 'Ones', score: null, description: 'Sum of all Ones'},
{name: 'Twos', score: null, description: 'Sum of all Twos'},
{name: 'Threes', score: null, description: 'Sum of all Threes'},
{name: 'Fours', score: null, description: 'Sum of all Fours'},
{name: 'Fives', score: null, description: 'Sum of all Fives'},
{name: 'Sixes', score: null, description: 'Sum of all Sixes'},
{name: '3 of a kind', score: null, description: 'Sum of all dice if 3 are the same'},
{name: '4 of a kind', score: null, description: 'Sum of all dice if 4 are the same'},
{name: 'Small Straight', score: null, description: '30 points for a small straight'},
{name: 'Large Straight', score: null, description: '40 points for a large straight'},
{name: 'Full House', score: null, description: '25 points for a full house'},
{name: 'YAHTZEE', score: null, description: '50 points for yahtzee'},
{name: 'Chance', score: null, description: 'Sum all dice'}
]
}
);
function rollDice() {
const newDice = gameState.dice.map((die) => {
return die.locked ? die : {...die, value: rollD()};
})
setGameState(prev => (
{
rollsLeft: prev.rollsLeft - 1,
dice: newDice
}), () => isYahtzee());
}
function resetRoll() {
setGameState(
{
dice: Array.from(Array(5)).map(i => ({value: rollD(), locked: false})),
rollsLeft: 2
}, () => isYahtzee()
)
}
function toggleDieLock(index) {
setGameState((prev) => {
return({
dice: prev.dice.map((die, i) => {
if(i === index) {
return {...die, locked: !die.locked};
} else {
return die
}
})
})
})
}
function isYahtzee() {
let yahtzeeDice;
for(let i = 0; i < gameState.dice.length - 1; i++) {
if (gameState.dice[i].value !== gameState.dice[i + 1].value) {
return setGameState({yahtzeeMode: false})
}
}
if(gameState.yahtzeeBonus) setGameState({yahtzeeMode: true})
}
function handleScore(name) {
let scoreValue = scoringFunctions[name](gameState.dice, gameState.yahtzeeMode);
let index;
let yahtzeeIndex;
for(let i = 0; i < gameState.scoreItems.length; i++) {
if(gameState.scoreItems[i].name === name) {
index = i;
}
if(gameState.scoreItems[i].name === 'YAHTZEE') {
yahtzeeIndex = i;
}
}
let updatedScoreItems = [...gameState.scoreItems];
updatedScoreItems[index].score = scoreValue;
setGameState((prev) => (
{
score: prev.score + scoreValue,
scoreItems: updatedScoreItems
}
), () => {updateBonus(yahtzeeIndex)})
resetRoll();
}
function updateBonus(yahtzeeIndex) {
if(!gameState.upperBonus) checkUpperBonus();
if(!gameState.yahtzeeBonus) {
updateYahtzeeState(yahtzeeIndex);
} else if(gameState.yahtzeeMode) {
setGameState((prev) => (
{
score: prev.score + 100,
yahtzeeBonus: prev.yahtzeeBonus + 1
}))
}
}
function checkUpperBonus() {
const totalUpper = gameState.scoreItems.slice(0, 6).reduce((total, item) => {
return item.score ? item.score + total : 0 + total;
}, 0);
if(totalUpper >= 63) {
setGameState((prev) => (
{
upperBonus: true,
score: prev.score + 35
}
))
}
}
function updateYahtzeeState(yahtzeeIndex) {
if(gameState.scoreItems[yahtzeeIndex].score) {
setGameState((prev) => ({yahtzeeBonus: prev.yahtzeeBonus + 1}))
}
}
return (
<div className="game">
<div className="header">
<div className="title">
<h1 className="h1">Yahtzee!</h1>
</div>
<Dice
dice={gameState.dice}
rollsLeft={gameState.rollsLeft}
rollDice={rollDice}
toggleDieLock={toggleDieLock}
yahtzeeMode={gameState.yahtzeeMode}
/>
</div>
<ScoreCard
dice={gameState.dice}
upperBonus={gameState.upperBonus}
yahtzeeBonus={gameState.yahtzeeBonus}
resetRoll={resetRoll}
handleScore={handleScore}
scoreItems={gameState.scoreItems}
/>
<div className="score-header">
<h2 className="score">{`Total Score: ${gameState.score}`}</h2>
</div>
</div>
)
}
export default Game;
功能组件 ScoreCard.js
import React from 'react';
import '../css/ScoreCard.css';
import ScoreItem from './ScoreItem';
const ScoreCard = props => {
const { handleScore, scoreItems} = props;
return <div className="scorecard">
<div className="scorecard__header">
<h2>Upper Section</h2>
</div>
{scoreItems.slice(0, 6).map(item => {
return <ScoreItem
key={item.name}
name={item.name}
score={item.score}
description={item.description}
handleScore={handleScore}
/>;
})}
<div className="scorecard__header">
<h2>Lower Section</h2>
</div>
{scoreItems.slice(6, 13).map(item => {
return <ScoreItem
key={item.name}
name={item.name}
score={item.score}
description={item.description}
handleScore={handleScore}
/>;
})}
</div>;
};
export default ScoreCard;
【问题讨论】:
标签: javascript reactjs