Reputation: 15558
I am rewriting ReactJS's "starter game" in ES6 with arrow functions (to remove the use of .bind()
, class properties and typescript.
Apparently in my code handleSquareClick
is triggered at rendering time, setState
is hence executed, resulting in error
Error: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.
Why?
Game.tsx:
import React, { PureComponent } from 'react';
import Board from "../Board";
class Game extends PureComponent {
state = {
history: [{
squares: Array(9).fill(null)
}],
currentStep: 0,
xIsNext: true
};
handleSquareClick = (i) => {
console.log(i);
// ...more code here
this.setState({
history: [...historyClone, { squares }],
currentStep: historyClone.length,
xIsNext: !xIsNext
});
};
render() {
const { history, currentStep } = this.state;
const current = history[currentStep];
return (
<div>
{ }
<Board
squares={current.squares}
handleSquareClick={this.handleSquareClick}
<
);
}
}
export default Game;
Board.tsx
import React, {PureComponent} from 'react';
import {
Title,
Square
} from './styles';
class Board extends PureComponent {
getSquareStringValue(value) {
if (value === 0) return 'X';
else if (value === 1) return 'O';
else return '';
}
renderSquare(props) {
const { key, value } = props;
return (
<Square
key={key}
className="square"
onClick={this.props.handleSquareClick(value)}>
{ this.getSquareStringValue(value) }
</Square>
)
}
render() {
const { title, squares } = this.props;
return (
<div className="board">
<Title>{title}</Title>
<div>
{[...Array(3).keys()]
.map((i) => (
<div className="board-row" key={i}>
{[...Array(3).keys()]
.map((j) => this.renderSquare({
key: (i+1)*(j+1),
value: squares[i]
}))
}
</div>
))
}
</div>
</div>
)
}
static defaultProps = {
title: "Board",
};
}
export default Board;
Board/styles.ts
import styled from 'styled-components';
export const Title = styled.h1`
font-size: 1rem;
`;
export const Square = styled.div`
height: 16px;
width: 16px;
border: 1px solid #000;
display: inline-block;
`;
Upvotes: 1
Views: 56
Reputation: 325
You just need to change this:
onClick={this.props.handleSquareClick(value)}>
to this:
onClick={()=> this.props.handleSquareClick(value)}>
because onClick
expects a function as a value, but what you were doing is that you were calling this function.
We know that if we put () at the end of a function, that function is called. So what I changed is to pass the function without calling it, by using a () => ...
arrow function.
Upvotes: 2