Reputation: 109
I'm in over my head with this. Creating connect 4 game and I'm stuck at the part where I need to update the chosen cells.
How it's behaving based on this code
The error:
undefined: {$$typeof: Symbol(react.element), type: "div", key: "06", ref: null, props: {…}, …}
createBoards = () => {
let gameBoard = []
for (let i = 0; i < 6; i++) {
gameBoard[i] = []
for (let j = 0; j < 7; j++) {
gameBoard[i].push(
<div className="box" key={[i]+[j]}>
<div
className="black"
id={[i]+[j]}
onClick={ (e) => this.playerMove(e)}>
</div>
</div>
)
}
}
this.setState({
gameBoard: gameBoard
}, function () {
console.log(this.state.gameBoard)
})
}
playerMove = (e) => {
let copyUserBoard = [...this.state.gameBoard]
let id = e.target.id
let i = e.target.id.split('').map(Number)
let element = copyUserBoard[i[0]][i[1]].props.children
let clonedElement = React.cloneElement(
element,
{ className: "red", key: id }
)
for (let i = 0; i < 6; i++) {
for (let j = 0; j < 7; j++) {
if (id === copyUserBoard[i][j].key) {
let newArr = Object.assign([], copyUserBoard, {[[i][j]]: clonedElement})
this.setState({
gameBoard: newArr
})
console.log(this.state.gameBoard)
}
}
}
}
Upvotes: 0
Views: 90
Reputation: 27245
I'd recommend that you maintain the state of the board independently of the DOM. Here's an example of how you might do it. Let me know if you have questions or anything needs clarification.
(I'm aware that this isn't how connect-four works. The point of this isn't the game mechanics, it's React state management.)
// how many boards to render
const NUM_BOARDS = 3;
// number of rows and columns
const BOARD_SIZE = 5;
// values for occupied cells,
// also used as css classes
const PLAYER_1 = 'p1';
const PLAYER_2 = 'p2';
// for convenience alternating players
const PLAYERS = [PLAYER_1, PLAYER_2];
// A React component for a row on a board.
// props.cells - an array of objects, each with
// a 'value' property whose value is PLAYER_1,
// PLAYER_2, or null
// props.onCellClick - a click handler for the
// to tell the board a particular cell was clicked.
const Row = ({cells, onCellClick}) => (
<ul className="row">
{
cells.map( ({value}, index) => (
<li key={index}
onClick={() => onCellClick(index)}
className={`cell ${value == null ? 'empty' : PLAYERS[value]}`}>
</li>
))
}
</ul>
)
class Board extends React.Component {
constructor (props) {
super(props);
this.state = {
player: 0,
rows: Array.from({length: BOARD_SIZE}, () => ({
cells: Array.from({length: BOARD_SIZE}, () => ({ value: null }))
}))
};
}
onCellClick = (row, cell) => {
const {rows, player} = this.state;
rows[row].cells[cell] = {value: player};
this.setState({
rows: [...rows],
player: (player + 1) % 2,
})
}
render () {
const {rows} = this.state;
return (
<div className="board">
<ul className="rows">
{rows.map((row, rowIndex) => (
<li key={rowIndex}><Row onCellClick={(cellIndex) => this.onCellClick(rowIndex, cellIndex)} cells={row.cells} /></li>
))}
</ul>
</div>
);
}
}
class ConnectFour extends React.Component {
render() {
return (
<div>
<ol>
{
// Emit the boards
Array.from({length: NUM_BOARDS}).map((_, i) => (
<li key={i}>
<Board />
</li>
))
}
</ol>
</div>
)
}
}
ReactDOM.render(<ConnectFour />, document.querySelector("#app"))
body {
padding: 20px;
}
ul, li {
padding: 0;
margin: 0;
list-style: none;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
.board {
--size: 40px;
padding: 10px;
margin: 10px auto;;
}
.row {
display: flex;
justify-content: center;
height: var(--size);
}
.row .cell {
flex: 0 0 var(--size);
margin: 1px;
}
.row > .empty {
background: #ccc;
}
.row > .cell.p1 {
background: red;
border-radius: 50%
}
.row > .cell.p2 {
background: blue;
border-radius: 50%
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>
Upvotes: 1