简体   繁体   English

如何将 React 组件分隔在不同的文件中以保持其正常工作并避免 TypeErrors?

[英]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.

相关问题 React.js:如何使用两个不同的独立 Button 组件下载两个不同的文件? - React.js: How can I download two different files with two different separate Button components? 如何将单独文件中的组件链接在一起以做出反应 - how to link components in separate files together in react 将React组件拆分为单独的文件 - Splitting React components into separate files 如何在单独的文件中正确存储React组件并导入React? - How to properly store React components in separate files and import React? 如何在我的 Discord 机器人中修复这些类型错误? - How can I fix these TypeErrors in my Discord bot? 如何在 React 中同步不同组件的身份验证状态? - How can I synchronize the authenticated status of different components in React? 如何在 React 的初始加载时有条件地渲染不同的组件? - How can I conditionally render different components on initial load in React? 如何根据可重用组件分离大型React代码库? - How can I separate a large React codebase based on re-usable components? 如何在保持可维护性的同时分离关注点(JS,HTML)? - How can I separate concerns (JS, HTML) while keeping maintainability? 如何在React中的不同文件中使用函数? - How can i use a function in different files in React?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM