Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

141
Views
Access and change the state array element in main React App from grandchild

I apologize for the headline of this question, but I tried to explain the problem as much as I could in one line.

Our school assignment required us to create a (sort of) Tic Tac Toe game but in a certain way. Instead of creating nine different Box elements from the main App, we were required to create Row class and Box class, so the main App will have three Row class children and each Row class will have three Box children.

Now the problem I encountered is how to change the main App state array at a particular element that corresponds to that exact Box component.

I am a beginner and I apologize in advance if I am not seeing something too obvious. If you have any questions, please do ask, I'll be more than happy to explain this as much as I can. Thank you!

    import React, { Component } from 'react';
    import { render } from 'react-dom';
    
    class App extends Component {
      constructor(props) {
        super(props);
        this.state = {
          0 : ['-','-','-'],
          1 : ['-','-','-'],
          2 : ['-','-','-']
        };
        this.handleClick = this.handleClick.bind(this)
      }
      handleClick(){
        // if that particular element is '-' change from '-' to 'X'
        // else if it is 'X' change to 'O'
        // else change to 'X'
      }
      render() {
    
        const rows = []
        for (let i = 0; i < 3; i++) {
          rows.push(<Row key = {i} msg = {this.state[i]} handleClick = {this.handleClick}/>)
        }
    
        return (
          <div>
            <div>
              <h1>Tic Tac Toe</h1>
            </div>
            <div id = 'main'>
              {rows}
            </div>
          </div>
        );
      }
    }
    class Row extends Component{
    
      render() {
        const boxes = []
        for (let i = 0; i < 3; i++) {
          boxes.push(<Box key = {i} msg = {this.props.msg[i]} handleClick = {this.props.handleClick}/>)
        }
        return (
          <div className = 'row'>
            {boxes}
          </div>
        )
      }
    
    }
    
    class Box extends Component{
    
      render() {
        return (
          <div className = 'box' onClick = {this.props.handleClick}>
            <p>{this.props.msg}</p>
          </div>
        )
      }
    
    }
    render(<App />, document.querySelector('#root'));
about 4 years ago · Juan Pablo Isaza
3 answers
Answer question

0

You have organized your components well. You need to handle player switching after each click and updating the values in the game board.

  1. Add another state variable called player (it can just be a boolean as this is a two-player game)
this.state = {
      0: ["-", "-", "-"],
      1: ["-", "-", "-"],
      2: ["-", "-", "-"],
      player: true
    };
  1. You can pass row and col index to handleClick function like below.
  handleClick(row, col) {
    // set the corresponding value (using row and colum index) in the game borad
    this.setState(
      {
        [row]: this.state[row].map((val, colId) =>
          colId === col ? (this.state.player ? "X" : "O") : val
        )
      },
      () => {
        // switch the player (toggle the player boolean value)
        this.setState({ player: !this.state.player });
      }
    );
  }
  1. Pass the row and col ids from the click handler in Box component.
       <Box
          ...
          ...
          handleClick={() => {
            this.props.handleClick(this.props.row, i);
          }}
        />

Code Sandbox

NOTE: when you develop further to avoid changing the same Box by clicking, you can keep an object to store more info like { value: "-", used: false } instead of "-" as values.

about 4 years ago · Juan Pablo Isaza Report

0

Building off of @Amila Senadheera's answer, you could also add a check in the handleClick function to ensure that a player can't overwrite another player's move. Something along the lines of:

handleClick(row, col) {
    // set the corresponding value (using row and colum index) in the game board
    if(this.state[row][col] !== '-') {
      return // Don't allow the player to overwrite an already-marked square.
    }
    this.setState(
      {
        [row]: this.state[row].map((val, colId) =>
          colId === col ? (this.state.player ? "X" : "O") : val
        )
      },
      () => {
        // switch the player (toggle the player boolean value)
        this.setState({ player: !this.state.player });
      }
    );
  }

And if you want to add a check for victory, there's some useful discussion here: https://codereview.stackexchange.com/questions/24764/tic-tac-toe-victory-check.

about 4 years ago · Juan Pablo Isaza Report

0

You could define parameters for handleClick like

type T = 1 | 2 | 3;
function handleClick(row: T, col: T) {
  const newRow = [ ...this.state[row] ];
  this.sign = this.sign === "O" ? "X" : "O";
  newRow[col] = this.sign;
  this.setState({...this.state, [row]: newRow});
}

and then you need new props for Box:

for (let i = 0; i < 3; i++) {
  boxes.push(
    <Box 
      row={props.row}
      col={i}
      key={i} 
      msg={this.props.msg[i]} 
      handleClick={this.props.handleClick}/>
  )
}
about 4 years ago · Juan Pablo Isaza Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!