[英]How can I separate React components in different files keeping it working and avoiding TypeErrors?
I'm implementing the reactjs.org tutorial, which is a tic-tac-toe game, but I'm trying to use hooks instead of classes as this tutorial does.我正在实施 reactjs.org 教程,这是一个井字游戏,但我正在尝试像本教程那样使用钩子而不是类。
This is the code I've wrote in a single file and is working fine:这是我在单个文件中编写的代码,并且运行良好:
function Square(props) {
return (
<button className="square" onClick={props.onClick}>
{props.value}
</button>
);
}
function Board(props) {
const renderSquare = (i) => {
return (
<Square
value={props.squares[i]}
onClick={() => props.onClick(i)}
/>
);
}
return (
<div>
<div className="board-row">
{renderSquare(0)}
{renderSquare(1)}
{renderSquare(2)}
</div>
<div className="board-row">
{renderSquare(3)}
{renderSquare(4)}
{renderSquare(5)}
</div>
<div className="board-row">
{renderSquare(6)}
{renderSquare(7)}
{renderSquare(8)}
</div>
</div>
);
}
function Game() {
const [clickedSquares, setClickedSquares] = useState(Array(9).fill(null))
const [xIsNext, setXIsNext] = useState(true)
const [moves, setMoves] = useState(0)
const [playsHistory, setPlaysHistory] = useState([{
history: {
squares: Array(9).fill(null)
},
xIsNext: true
}])
const index = 0
const determineWinner = (squares) => {
const lines = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[0, 3, 6],
[1, 4, 7],
[2, 5, 8],
[0, 4, 8],
[2, 4, 6],
];
for (let i = 0; i < lines.length; i++) {
const [a, b, c] = lines[i];
if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {
return squares[a];
}
}
return null;
}
const handleClick = (i) => {
const squares = clickedSquares.slice()
if (determineWinner(squares) || squares[i]) return
squares[i] = xIsNext ? 'X' : 'O';
// console.log(xIsNext)
setXIsNext(!xIsNext)
// console.log(xIsNext)
let current = playsHistory
current ={
history:{
squares: squares},
xIsNext: !xIsNext
}
// console.log(current)
setClickedSquares(squares)
setMoves(prevMoves => prevMoves + 1)
setPlaysHistory(prevPlays => ([...prevPlays, current]))
console.log(playsHistory)
}
let winner = determineWinner(clickedSquares)
let status = winner ? `Winner: ${winner}` : `Next player: ${xIsNext ? 'X' : 'O'}`
if(!winner && moves === 9) status = 'Draw'
return (
<div className="game">
<div className="game-board">
<Board
squares={clickedSquares}
onClick={(i) => handleClick(i)}
/>
</div>
<div className="game-info">
<div>{status}</div>
<ol>{/* TODO */}</ol>
</div>
</div>
);
}
export default Game
I'm done with the most of the functionalities, however I've been working in a single file.我已经完成了大部分功能,但是我一直在一个文件中工作。 So I've tried to refactor my project dividing its functions in smaller files for each component.
因此,我尝试重构我的项目,将其功能划分为每个组件的较小文件。 I've created three component files:
我创建了三个组件文件:
Square.jsx
: Square.jsx
:
function Square(props) {
return (
<button className="square" onClick={props.onClick}>
{props.value}
</button>
);
}
export default Square
Board.jsx
: Board.jsx
:
function Board(props) {
const renderSquare = (i) => {
return (
<Square
value={props.squares[i]}
onClick={() => props.onClick(i)}
/>
);
}
return (
<div>
<div className="board-row">
{renderSquare(0)}
{renderSquare(1)}
{renderSquare(2)}
</div>
<div className="board-row">
{renderSquare(3)}
{renderSquare(4)}
{renderSquare(5)}
</div>
<div className="board-row">
{renderSquare(6)}
{renderSquare(7)}
{renderSquare(8)}
</div>
</div>
);
}
export default Board;
and Game.jsx
:和
Game.jsx
:
function Game() {
const [clickedSquares, setClickedSquares] = useState(Array(9).fill(null))
const [xIsNext, setXIsNext] = useState(true)
const [moves, setMoves] = useState(0)
const [playsHistory, setPlaysHistory] = useState([{
history: {
squares: Array(9).fill(null)
},
xIsNext: true
}])
const determineWinner = (squares) => {
const lines = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[0, 3, 6],
[1, 4, 7],
[2, 5, 8],
[0, 4, 8],
[2, 4, 6],
];
for (let i = 0; i < lines.length; i++) {
const [a, b, c] = lines[i];
if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {
return squares[a];
}
}
return null;
}
const handleClick = (i) => {
const squares = clickedSquares.slice()
squares[i] = xIsNext ? 'X' : 'O';
// console.log(xIsNext)
setXIsNext(!xIsNext)
// console.log(xIsNext)
let current = playsHistory
current ={
history:{
squares: squares},
xIsNext: !xIsNext
}
// console.log(current)
setClickedSquares(squares)
setMoves(prevMoves => prevMoves + 1)
setPlaysHistory(prevPlays => ([...prevPlays, current]))
console.log(playsHistory)
if (determineWinner(squares) || squares[i]) return
}
let winner = determineWinner(clickedSquares)
let status = winner ? `Winner: ${winner}` : `Next player: ${xIsNext ? 'X' : 'O'}`
if(!winner && moves === 9) status = 'Draw'
return (
<div className="game">
<div className="game-board">
<Board
squares={clickedSquares}
onClick={(i) => handleClick(i)}
/>
</div>
<div className="game-info">
<div>{status}</div>
<ol>{/* TODO */}</ol>
</div>
</div>
);
}
export default Game;
Now, I'm receiving TypeError:Cannot read property '0' of undefined
error at this point of Board component:现在,我收到
TypeError:Cannot read property '0' of undefined
error at this point of Board 组件:
7 | const renderSquare = (i) => {
8 | return (
9 | <Square
> 10 | value={props.squares[i]}
| ^ 11 | onClick={() => props.onClick(i)}
12 | />
13 | );
If I set the same code in a single.jsx file, it works well.如果我在单个 .jsx 文件中设置相同的代码,它运行良好。 I already removed the
[i]
from props.squares
at line 10, however a new error occours TypeError: props.onClick is not a function
.我已经从第 10 行的
props.squares
中删除了[i]
,但是出现了一个新错误TypeError: props.onClick is not a function
。 I think Board.jsx
file doesn't recognizes the parameters I'm passing from Game.jsx
file.我认为
Board.jsx
文件无法识别我从Game.jsx
文件传递的参数。 How should I componentize my project in different files and keep it working?我应该如何将我的项目组件化到不同的文件中并保持工作?
You have to be very careful while separating the components.分离组件时必须非常小心。 Check out this CodeSandbox link.
查看此CodeSandbox链接。 I haven't done any changes in your logic.
我没有对您的逻辑进行任何更改。 There is a scope for code improvement but that wasn't in the requirements so I have just separated your file into individual components file.
有一个 scope 用于代码改进,但这不在要求中,所以我刚刚将您的文件分成单独的组件文件。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.