I apologize for the headline of this question, but I tried to explain the problem as much as I could in one line.
Our school assignment required us to create a (sort of) Tic Tac Toe game but in a certain way. Instead of creating nine different Box elements from the main App, we were required to create Row class and Box class, so the main App will have three Row class children and each Row class will have three Box children.
Now the problem I encountered is how to change the main App state array at a particular element that corresponds to that exact Box component.
I am a beginner and I apologize in advance if I am not seeing something too obvious. If you have any questions, please do ask, I'll be more than happy to explain this as much as I can. Thank you!
import React, { Component } from 'react';
import { render } from 'react-dom';
class App extends Component {
constructor(props) {
super(props);
this.state = {
0 : ['-','-','-'],
1 : ['-','-','-'],
2 : ['-','-','-']
};
this.handleClick = this.handleClick.bind(this)
}
handleClick(){
// if that particular element is '-' change from '-' to 'X'
// else if it is 'X' change to 'O'
// else change to 'X'
}
render() {
const rows = []
for (let i = 0; i < 3; i ) {
rows.push(<Row key = {i} msg = {this.state[i]} handleClick = {this.handleClick}/>)
}
return (
<div>
<div>
<h1>Tic Tac Toe</h1>
</div>
<div id = 'main'>
{rows}
</div>
</div>
);
}
}
class Row extends Component{
render() {
const boxes = []
for (let i = 0; i < 3; i ) {
boxes.push(<Box key = {i} msg = {this.props.msg[i]} handleClick = {this.props.handleClick}/>)
}
return (
<div className = 'row'>
{boxes}
</div>
)
}
}
class Box extends Component{
render() {
return (
<div className = 'box' onClick = {this.props.handleClick}>
<p>{this.props.msg}</p>
</div>
)
}
}
render(<App />, document.querySelector('#root'));
CodePudding user response:
You have organized your components well. You need to handle player switching after each click and updating the values in the game board.
- Add another state variable called
player(it can just be a boolean as this is a two-player game)
this.state = {
0: ["-", "-", "-"],
1: ["-", "-", "-"],
2: ["-", "-", "-"],
player: true
};
- You can pass row and col index to
handleClickfunction like below.
handleClick(row, col) {
// set the corresponding value (using row and colum index) in the game borad
this.setState(
{
[row]: this.state[row].map((val, colId) =>
colId === col ? (this.state.player ? "X" : "O") : val
)
},
() => {
// switch the player (toggle the player boolean value)
this.setState({ player: !this.state.player });
}
);
}
- Pass the
rowandcolids from the click handler inBoxcomponent.
<Box
...
...
handleClick={() => {
this.props.handleClick(this.props.row, i);
}}
/>
NOTE: when you develop further to avoid changing the same Box by clicking, you can keep an object to store more info like { value: "-", used: false } instead of "-" as values.
CodePudding user response:
You could define parameters for handleClick like
type T = 1 | 2 | 3;
function handleClick(row: T, col: T) {
const newRow = [ ...this.state[row] ];
this.sign = this.sign === "O" ? "X" : "O";
newRow[col] = this.sign;
this.setState({...this.state, [row]: newRow});
}
and then you need new props for Box:
for (let i = 0; i < 3; i ) {
boxes.push(
<Box
row={props.row}
col={i}
key={i}
msg={this.props.msg[i]}
handleClick={this.props.handleClick}/>
)
}
CodePudding user response:
Building off of @Amila Senadheera's answer, you could also add a check in the handleClick function to ensure that a player can't overwrite another player's move. Something along the lines of:
handleClick(row, col) {
// set the corresponding value (using row and colum index) in the game board
if(this.state[row][col] !== '-') {
return // Don't allow the player to overwrite an already-marked square.
}
this.setState(
{
[row]: this.state[row].map((val, colId) =>
colId === col ? (this.state.player ? "X" : "O") : val
)
},
() => {
// switch the player (toggle the player boolean value)
this.setState({ player: !this.state.player });
}
);
}
And if you want to add a check for victory, there's some useful discussion here: https://codereview.stackexchange.com/questions/24764/tic-tac-toe-victory-check.
