0

So I am making a tic-tac-toe project on react JS and I have to pass the key of the square component which is actually the child component to the game component (parent component) for developing the checkWinner function. Please guide me how to pass it as I have to locate the value of every square component through the keys.

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
import React from "react";
//---Square component-->
function Square (props) {
  /*Lifting state to parent Component as to store the changes of 
  all the squares -> for maintaining the winner */
  return (
      <button className="square" onClick={() => props.onClick()}>
        {/* when the square is clicked
    then it will call the handleClick 
    function in board component  */}

        {props.value}
      </button>
    );
  
}

export default Square;

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
import React from "react";
import Board from "./Board";
import { array } from "prop-types";
//--Game component--

<!-- begin snippet: js hide: false console: true babel: false -->
class Game extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      size: null,
      history: [{ squares: Array(this.size).fill(null) }],
      /*Array of 9 items filled with null
      for all the 9 squares */
      stepNumber: 0,
      board: [{ squares: Array(this.size).fill(null) }],
      xIsNext: true /*By default the X has first move*/,
    };
    this.input = this.input.bind(this);

  }
  jumpTo(step) {
    this.setState({
      stepNumber: step,
      xIsNext: step % 2 === 0 /*it will be true ->even */,
    });
  }
  handleClick(i) {

    const history = this.state.history.slice(0, this.state.stepNumber + 1);
    const current = history[history.length - 1];

    const squares = current.squares.slice();
    if (this. calculateWinner(squares) || squares[i]) {
      return;
    }
    squares[i] = this.state.xIsNext
      ? "X"
      : "O"; /* changing the value of the square which is clicked*/
    this.setState({
      history: history.concat([
        { squares: squares },
      ]) /*Now changing the state as it requires setState */,
      stepNumber: history.length,
      xIsNext: !this.state.xIsNext,
    }); /*Everytime move is flipped when clicked on the square */
  }
  input() {
    let n = parseInt(document.getElementById("text").value);
    this.setState({
      size: n,
      history: [{ squares: Array(n).fill(null) }],
      board:[{squares:Array(n).fill(null)}]
    });
  }

  render() {
    const history = this.state.history;
    const current = history[this.state.stepNumber];
    const winner = this.calculateWinner(current.squares);

    const moves = history.map((step, move) => {
      const desc = move ? "Go to move #" + move : "Go to game start";
      return (
        <li key={move}>
          <button onClick={() => this.jumpTo(move)}>{desc}</button>
        </li>
      );
    });

    let status;
    if (winner) {
      status = "Winner: " + winner;
    } else {
      status = "Next player: " + (this.state.xIsNext ? "X" : "O");
    }

    return (
      <div>
        <label>Board Size: </label>
        <input
          type="number"
          id="text"
          size="11"
          placeholder="Enter board size"
        />
        <button onClick={this.input}>Submit</button>
        <div className="game">
          <div className="game-board">
            <Board
              size={this.state.size}
              squares={current.squares}
              onClick={(i) => this.handleClick(i)}
            />
          </div>
          <div className="game-info">
            <div>{status}</div>
            <ol>{moves}</ol>
          </div>
        </div>
      </div>
    );
  }
calculateWinner(squares) {
    // Check each of 3 rows:
    let lines=[0,1,2];
    let array=[];
  for(let j=0;j<(this.state.size*this.state.size)-1;j++){
    array.push(lines);

  }

    // const lines = [
    //   // /*Tells the location for X and O */
    //    [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 <array.length; i++) {
      const [a, b, c] = array[i]

      /*Squares tells the array for X and o where they are stored */
      if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {
        console.log(squares[a]);
        return squares[a];
      }
    }
    return null;


  }
}

export default Game;
Zoha Akram
  • 47
  • 9

1 Answers1

0

When you want to pass data from child to parent component that usually mean that your parent has a state and you want to allow child component to update this state.

Check out this example: https://codesandbox.io/s/passing-data-to-parent-component-dmrm8?file=/src/App.js

As you can see <App /> component has submittedText variable in it's state. <App /> component also defines setSubmittedText function that changes value of this variable. Then we pass setSubmittedText function to <Child /> component, in that way we allow <Child /> component to change submittedText variable. This is how <Child /> component passes data to parent component. Since <App /> component owns submittedText state now it knows when it's value changed. Now you can render anything you want in <App /> component based on submittedText value or do some actions using useEffect hook whenever submittedText changed.