我如何将不同文件中的 React 组件分开以保持其正常工作并避免 TypeErrors?
How can I separate React components in different files keeping it working and avoiding TypeErrors?
我正在实现 reactjs.org 教程,这是一个井字游戏,但我正在尝试使用挂钩而不是本教程中使用的 类。
这是我在单个文件中编写的代码,运行良好:
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
我已经完成了大部分功能,但是我一直在处理单个文件。因此,我尝试重构我的项目,将其功能划分为每个组件的较小文件。我创建了三个组件文件:
Square.jsx
:
function Square(props) {
return (
<button className="square" onClick={props.onClick}>
{props.value}
</button>
);
}
export default Square
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;
和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;
现在,我在 Board 组件的这一点收到 TypeError:Cannot read property '0' of undefined
错误:
7 | const renderSquare = (i) => {
8 | return (
9 | <Square
> 10 | value={props.squares[i]}
| ^ 11 | onClick={() => props.onClick(i)}
12 | />
13 | );
如果我在单个 .jsx 文件中设置相同的代码,效果很好。我已经从第 10 行的 props.squares
中删除了 [i]
,但是出现了新的错误 TypeError: props.onClick is not a function
。我认为 Board.jsx
文件无法识别我从 Game.jsx
文件传递的参数。我应该如何将我的项目组件化到不同的文件中并使其正常运行?
分离组件时必须非常小心。看看这个 CodeSandbox link。我没有对你的逻辑做任何改变。有代码改进的余地,但这不在要求中,所以我刚刚将您的文件分成单独的组件文件。
我正在实现 reactjs.org 教程,这是一个井字游戏,但我正在尝试使用挂钩而不是本教程中使用的 类。
这是我在单个文件中编写的代码,运行良好:
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
我已经完成了大部分功能,但是我一直在处理单个文件。因此,我尝试重构我的项目,将其功能划分为每个组件的较小文件。我创建了三个组件文件:
Square.jsx
:
function Square(props) {
return (
<button className="square" onClick={props.onClick}>
{props.value}
</button>
);
}
export default Square
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;
和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;
现在,我在 Board 组件的这一点收到 TypeError:Cannot read property '0' of undefined
错误:
7 | const renderSquare = (i) => {
8 | return (
9 | <Square
> 10 | value={props.squares[i]}
| ^ 11 | onClick={() => props.onClick(i)}
12 | />
13 | );
如果我在单个 .jsx 文件中设置相同的代码,效果很好。我已经从第 10 行的 props.squares
中删除了 [i]
,但是出现了新的错误 TypeError: props.onClick is not a function
。我认为 Board.jsx
文件无法识别我从 Game.jsx
文件传递的参数。我应该如何将我的项目组件化到不同的文件中并使其正常运行?
分离组件时必须非常小心。看看这个 CodeSandbox link。我没有对你的逻辑做任何改变。有代码改进的余地,但这不在要求中,所以我刚刚将您的文件分成单独的组件文件。