skip to Main Content

this is my code so far by following official react js tutorial of making a tic-tac-toe game, I able to complete the game, but struct on the 1st challenge of create square using loop instead of hardcoding it, as you can see the comment part of code.

import { useState } from "react";

function Square({ value, onSquareClick }) {
    return (
        <button className="square" onClick={onSquareClick} >{value}</button>
    );
}

function CreateSquares(squares, handleClick) {

    const data = [];
    for (let i = 0; i < 3; i++) {
        const rows = [];
        for (let j = 0; j < 3; j++) {
            rows.push(
                <Square value={squares[j]} onSquareClick={() => handleClick(j)} key={j} />
            );
        }
        data.push(
            <div className="board-row" key={i}>{rows}</div>
        );
    }
    return data;
}

function Board({ xIsNext, squares, onPlay }) {

    let winner = calculateWinner(squares);

    function handleClick(index) {
        if (squares[index] || winner) {
            return;
        }
        const nextSquares = squares.slice();

        nextSquares[index] = xIsNext ? 'X' : 'O';

        onPlay(nextSquares);
    }
    let status = winner ? "Winner: " + winner : "Next Player: " + (xIsNext ? "X" : "O");

    return (
        <>
            <div className="status">{status}</div>
            <CreateSquares squares={squares} handleClick={handleClick} />
            {/* <div className="board-row">
                <Square value={squares[0]} onSquareClick={() => handleClick(0)} />
                <Square value={squares[1]} onSquareClick={() => handleClick(1)} />
                <Square value={squares[2]} onSquareClick={() => handleClick(2)} />
            </div>
            <div className="board-row">
                <Square value={squares[3]} onSquareClick={() => handleClick(3)} />
                <Square value={squares[4]} onSquareClick={() => handleClick(4)} />
                <Square value={squares[5]} onSquareClick={() => handleClick(5)} />
            </div>
            <div className="board-row">
                <Square value={squares[6]} onSquareClick={() => handleClick(6)} />
                <Square value={squares[7]} onSquareClick={() => handleClick(7)} />
                <Square value={squares[8]} onSquareClick={() => handleClick(8)} />
            </div> */}
        </>
    );
}

export default function Game() {
    const [history, setHistory] = useState([Array(9).fill(null)]);
    const [currentMove, setCurrentMove] = useState(0);
    const xIsNext = currentMove % 2 === 0;
    const currentSquares = history[currentMove];

    function handlePlay(nextSquares) {
        const nextHistory = [...history.slice(0, currentMove + 1), nextSquares];
        setHistory(nextHistory);
        setCurrentMove(nextHistory.length - 1);
    }

    function jumpTo(nextMove) {
        setCurrentMove(nextMove);
    }

    const moves = history.map((squares, move) => {
        let description = move > 0 ? 'Go to move #' + move : "Go to game start";

        return (
            <li key={move}>
                <button onClick={() => { jumpTo(move) }}>{description}</button>
            </li>
        );
    });

    return (
        <div className="game">
            <div className="game-board">
                <Board xIsNext={xIsNext} squares={currentSquares} onPlay={handlePlay} />
            </div>
            <div className="game-info">
                <ol>{moves}</ol>
            </div>
        </div>
    );
}

function calculateWinner(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]
    ];

    let len = lines.length;
    for (let i = 0; i < len; i++) {
        const [a, b, c] = lines[i];
        if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {
            return squares[a];
        }
    }

    return null;
}

this is the error i’m getting and i’m not able to figure out how to fix this.

    handleClick is not a function
    TypeError: handleClick is not a function
    at onSquareClick (http://localhost:3000/main.9d076070d9e17e2c1932.hot-update.js:51:30)
    at HTMLUnknownElement.callCallback (http://localhost:3000/static/js/bundle.js:10826:18)
    at Object.invokeGuardedCallbackDev (http://localhost:3000/static/js/bundle.js:10870:20)
    at invokeGuardedCallback (http://localhost:3000/static/js/bundle.js:10927:35)
    at invokeGuardedCallbackAndCatchFirstError (http://localhost:3000/static/js/bundle.js:10941:29)
    at executeDispatch (http://localhost:3000/static/js/bundle.js:15085:7)
    at processDispatchQueueItemsInOrder (http://localhost:3000/static/js/bundle.js:15111:11)
    at processDispatchQueue (http://localhost:3000/static/js/bundle.js:15122:9)
    at dispatchEventsForPlugins (http://localhost:3000/static/js/bundle.js:15131:7)
    at http://localhost:3000/static/js/bundle.js:15291:16

i’m trying to learn react and struct here, I already studied official quick start guide 2-3 times, but still not able to figure out what i am doing wrong, any help will be appreciated

3

Answers


  1. Chosen as BEST ANSWER

    Made it working and here is the working solution

    import { useState } from "react";
    
    function Square({ value, onSquareClick }) {
        return (
            <button className="square" onClick={onSquareClick} >{value}</button>
        );
    }
    
    function CreateSquares({ squares, checkClick }) {
    
        const data = [];
        for (let i = 0; i < 3; i++) {
            const rows = [];
            for (let j = 0; j < 3; j++) {
    
                const index = i * 3 + j; // Calculate a unique index for each square
    
                rows.push(
                    <Square value={squares[index]} onSquareClick={() => checkClick(index)} key={index} />
                );
            }
            data.push(
                <div className="board-row" key={i}>{rows}</div>
            );
        }
        return data;
    }
    
    function Board({ xIsNext, squares, onPlay }) {
    
        let winner = calculateWinner(squares);
    
        function handleClick(index) {
    
            if (squares[index] || winner) {
                return;
            }
            const nextSquares = squares.slice();
    
            nextSquares[index] = xIsNext ? 'X' : 'O';
    
            onPlay(nextSquares);
        }
        let status = winner ? "Winner: " + winner : "Next Player: " + (xIsNext ? "X" : "O");
    
        return (
            <>
                <div className="status">{status}</div>
                <CreateSquares squares={squares} checkClick={handleClick} />
            </>
        );
    }
    
    export default function Game() {
        const [history, setHistory] = useState([Array(9).fill(null)]);
        const [currentMove, setCurrentMove] = useState(0);
        const xIsNext = currentMove % 2 === 0;
        const currentSquares = history[currentMove];
    
        function handlePlay(nextSquares) {
            const nextHistory = [...history.slice(0, currentMove + 1), nextSquares];
            setHistory(nextHistory);
            setCurrentMove(nextHistory.length - 1);
        }
    
        function jumpTo(nextMove) {
            setCurrentMove(nextMove);
        }
    
        const moves = history.map((squares, move) => {
            let description = move > 0 ? 'Go to move #' + move : "Go to game start";
    
            return (
                <li key={move}>
                    <button onClick={() => { jumpTo(move) }}>{description}</button>
                </li>
            );
        });
    
        return (
            <div className="game">
                <div className="game-board">
                    <Board xIsNext={xIsNext} squares={currentSquares} onPlay={handlePlay} />
                </div>
                <div className="game-info">
                    <ol>{moves}</ol>
                </div>
            </div>
        );
    }
    
    function calculateWinner(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]
        ];
    
        let len = lines.length;
        for (let i = 0; i < len; i++) {
            const [a, b, c] = lines[i];
            if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {
                return squares[a];
            }
        }
    
        return null;
    }
    

    I needed to pass

    <CreateSquares squares={squares} checkClick={handleClick} />
    

    and need to do this

    function CreateSquares({ squares, checkClick }) {
    

    instead of this

    function CreateSquares( squares, checkClick ) {
    

  2. // Move the handleClick function outside the Board component
    function handleClick() {
      // Your code logic here
    }
    
    function Board() {
      // Board component code
    
      return (
        // JSX code
      );
    }
    
    // Rename the handleClick function to avoid type errors
    const handleClickOutsideBoard = handleClick;
    
    // Call the handleClickOutsideBoard function from outside the Board component
    handleClickOutsideBoard();
    
    

    In this code, we moved the handleClick function outside the Board component so that it can be accessed from outside. We also renamed the function to handleClickOutsideBoard to avoid any potential type errors. You can then call the handleClickOutsideBoard function from anywhere outside the Board component.

    Login or Signup to reply.
  3. function CreateSquares(squares, handleClick) {
    
        function checkClick(index) {
            handleClick(index);
        }
        const data = [];
        for (let i = 0; i < 3; i++) {
            const rows = [];
            for (let j = 0; j < 3; j++) {
                rows.push(
                    <Square value={squares[j]} onSquareClick={() => handleClick(j)} key={j} />
                );
            }
            data.push(
                <div className="board-row" key={i}>{rows}</div>
            );
        }
        return data;
    }
    

    in this part of code i think you’re incorrectly calling handleClick function ( i.e wrong index being passed , instead you have to pass unique index for each square based on rows and col ).

    try this and let me know :

    function CreateSquares(squares, handleClick) {
      function checkClick(index) {
        handleClick(index);
      }
    
      const data = [];
      for (let i = 0; i < 3; i++) {
        const rows = [];
        for (let j = 0; j < 3; j++) {
          const index = i * 3 + j; // Calculate a unique index for each square
          rows.push(
            <Square
              value={squares[index]}
              onSquareClick={() => handleClick(index)}
              key={index}
            />
          );
        }
        data.push(<div className="board-row" key={i}>{rows}</div>);
      }
      return data;
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search