如何将 React 组件分离到不同的文件中以使其正常工作并避免 TypeErrors?
Posted
技术标签:
【中文标题】如何将 React 组件分离到不同的文件中以使其正常工作并避免 TypeErrors?【英文标题】:How can I separate React components in different files keeping it working and avoiding TypeErrors? 【发布时间】:2021-08-12 09:07:08 【问题描述】:我正在实现 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
文件传递的参数。我应该如何将我的项目组件化到不同的文件中并保持其正常工作?
【问题讨论】:
【参考方案1】:分离组件时必须非常小心。看看这个CodeSandbox 链接。我没有对您的逻辑进行任何更改。代码有改进的余地,但这不在要求中,所以我只是将您的文件分成单独的组件文件。
【讨论】:
以上是关于如何将 React 组件分离到不同的文件中以使其正常工作并避免 TypeErrors?的主要内容,如果未能解决你的问题,请参考以下文章
jquery-select2 - 将 select2 添加到现有的下拉代码中以使其可搜索