Access to array element / React

Hi! I’m struggling with getting access to the Array[80] (I would like to change color this array).
I would be grateful for any help.

class Grid extends React.Component {
    constructor(props){
        super(props);
        this.state = {
            grid: this.generateGrid(15,15)
        };
    }

    generateGrid(cols, rows, value) {
        let array = [];
        for(let i=0; i < rows; i++) {
            array.push([]);
            array[i].push( new Array(cols));

            for(let j=0; j < cols; j++) {
                array[i][j] = value;
            }
        }

        return array;
    }

    render() {
        return (
            <div
                className="grid" style={{backgroundColor:"LightGray", border:"2px solid black", width: "auto", height:"auto", position:"absolute", left:"55px", top:"120px"}}>
                <table>
                    <tbody>
                    {this.state.grid.map((row, i) =>
                        <tr key={i}>
                            {row.map((col, j) =>
                                <td key={j} style={{backgroundColor:"pink", border:"1px solid black", width: "20px", height:"20px"}}>{col}</td>
                            )}
                        </tr>
                    )}
                    </tbody>
                </table>
            </div>
        )
    }
}

I’ve edited your post for readability. When you enter a code block into the forum, precede it with a line of three backticks and follow it with a line of three backticks to make easier to read. See this post to find the backtick on your keyboard. The “preformatted text” tool in the editor (</>) will also add backticks around text.

markdown_Forums

1 Like

You need some kind of logic to change square 80. The point of React is that you build the logic into the component and then you change the data and the view changes automatically. That is one way data binding. You need to tell Grid what logic will determine what you want to happen.

This is a silly example targeting square 80:

    render() {
        const styleBox = (i, j) => {
            return {
                backgroundColor: (i*15+j===80)?'green':'pink',
                border: "1px solid black",
                width: "20px",
                height: "20px"
            }
        }
    
        return (
            <div
                className="grid" style={{backgroundColor:"LightGray", border:"2px solid black", width: "auto", height:"auto", position:"absolute", left:"55px", top:"120px"}}>
                <table>
                    <tbody>
                    {this.state.grid.map((row, i) =>
                        <tr key={i}>
                            {row.map((col, j) =>
                                <td key={j} style={styleBox(i, j)}>{col}</td>
                            )}
                        </tr>
                    )}
                    </tbody>
                </table>
            </div>
        )
    }

What you really need to do is create a 15X15 array of data and then have your render function style those boxes depending on what that data is. Preferably the array is not in local state, but is passed up as props. That way when the parent component changes its state (and changing Grid’s props) then Grid will automatically change the screen. That is how React is supposed to work.

Thank you Kevin for your help, I really appreciate it!

Could you tell me please also what shall I do If I would like to put this array into a movement (I created commands, but don’t know how to put them together).

handleKey = (e) => {
        const direction = e.keyCode;
        // console.log(direction);
        switch(e.keyCode) {
            case 37:
            console.log("LEFT");
                if(this.props.direction !== "RIGHT" && this.props.moving){
                    this.props.changeDirection("LEFT")
                }
                break;
            case 38:
            console.log("UP");
                if(this.props.direction !== "DOWN" && this.props.moving){
                    this.props.changeDirection("UP")
                }
                break;
            case 39:
            console.log("RIGHT");
                if(this.props.direction !== "LEFT" && this.props.moving){
                    this.props.changeDirection("RIGHT")
                }
                break;
            case 40:
            console.log("DOWN");
                if(this.props.direction !== "UP" && this.props.moving) {
                    this.props.changeDirection("DOWN")
                }
                break;
            default:
                break;
        }
    }

Again, React has one way data binding. If you create the view from the data, and then you change the data, the view will automatically change. I would consider a structure like this:

Game --|
       |--Controls
       |--Grid

So, Game is the parent, and Controls and Grid are children. You are going to keep state in Game - that is where your data structure of 15X15 will be. You will decide what that data is. Maybe they are arrays of numbers and a 0 means empty and 1 means your player is there. Or it could be an object with a bunch of values - it;s up to you.

That part of the state will be passed to Grid where it will be received as props and you will conditionally render each of those squares based on the values in that data structure. Grid doesn’t know where those numbers are coming from and doesn’t care - it just know that if the data for this square is 0, the square is pink and if it is 1, the square is green (or whatever.) Part of the magic of React is that you don’t have to worry about the grid on the screen after that - if you change the data in the state of Game, then Grid will automatically update. This is one way data binding. The view is bound to the data - when the data changes, the view automatically updates. Anytime your view is dependent on something in state or something passed in as props, React does this for you.

Now, how do you change them? I would have that child component called Controls. You could do it in Game - and on the surface that would be easier - but it is bad coding practice and would be unwieldy in a large program. So, you have a component called Controls that handles all the input. So, how does the child affect the state of the parent? The parent passes a function as props that the child can call to change the state of the parent.

So Controls sees a left arrow. It calls the function given to it in props, maybe something called movePlayer(). We pass it an argument, maybe a string of value ‘left’. Back in Game, that function gets called. That function does that math - if it’s as grid (4, 5), then we need to change it to (3, 5). (For convenience, you probably have these is state in a separate variable from the grid.) You update those variables and update the grid (all using setState or course) - the grid is change - (4, 5) becomes 0 and (3, 5) becomes 1 - or however you are keeping track of where the player is.

Now, because we just changed the grid in the state of the parent, and that variable is being passed the the child Grid, Grid will automatically change to reflect the new data. This is the magic of React and one way data binding.

This process of passing data and functions back and forth is difficult at first. Here is a simple pen I wrote to show how this happens.

I suppose I might also point out something that confused me when I was learning React. State is not shared between components. Every component has its own state. Read that again. This is very important. Any data you want to share has to be passed as props (going from parent to child) or in a callback function (child to parent). In complex apps, you may have to pass it through a couple layers to get to where it is going.

But because of this “no shared state” principle, it is best to have one place where you store the state of the app, ideally the ancestor of all the components that need that state. Sometimes you have components that use their own state for things that only they need, like the input of a text box, etc.

As mentioned, these component trees can get complex and difficult to pass data around. That is why things like Flux, Redux, and Mobx exist. But for these projects, it is probably best just to get a handle on React first.

Yes. React is difficult. Yes, the material is insufficient. But you’ll get through it. I recommend seeking out some youtube code-along tutorials. Eventually it will click.

Let us know if anything needs clarification.

2 Likes

Kevin Thank you so much for your response. It’s really helpful, but still, I don’t understand a few things (or maybe I’m really confused). I feel I have to clear my code and start again.

I’ve created App component, which is my “parent”:

class App extends React.Component{
    constructor(props){
      super(props)
      this.state={
        direction: "DOWN",
        moving: true,
        score: 0,
        dataArray: [0,1],
      }
    }
    changeDirection = (data)=>{
      console.log("Change direction in app from:",this.state.direction,"to:",data);

      this.setState({
        direction: data
      })
    }
    render(){
        return (
            <div  className="app">
                <Board score={this.state.score}/>
                <Grid />
                <Snake direction={this.state.direction} moving={this.state.moving} changeDirection={this.changeDirection} />
            </div>
        )
    }
}


document.addEventListener('DOMContentLoaded', function(){
    ReactDOM.render(
        <App />,
        document.getElementById('app')
    );
});

then I’ve created Board (one of the children), where are the title and score information:

class Board extends React.Component {
    constructor(props){
        super(props);
    }
    render() {
      const boardStyles = {backgroundColor: "MistyRose", border:"1px solid black", width: "500px", height: "540px", position:"relative"}
        return (
            <div className="board" style={boardStyles}>
                <h1>Snake Game</h1>
                <div>
                    <span> Score: {this.props.score}</span>
                </div>
            </div>
        )
    }
}

Here is my grid component (another child), which finally I don’t know if shall I delete it and put everything on the Board?.

class Grid extends React.Component {
    constructor(props){
        super(props);
        this.state = {
            grid: this.generateGrid(15,15)
            dataArray: [0,1],

        };
    }

    generateGrid(cols, rows, value) {
        let array = [];
        for(let i=0; i < rows; i++) {
            array.push([]);
            array[i].push( new Array(cols));

            for(let j=0; j < cols; j++) {
                array[i][j] = value;
            }
        }

        return array;
    }

    render() {
        return (
            <div
                className="grid" style={{backgroundColor:"LightGray", border:"2px solid black", width: "auto", height:"auto", position:"absolute", left:"55px", top:"120px"}}>
                <table>
                    <tbody>
                    {this.state.grid.map((row, i) =>
                        <tr key={i}>
                            {row.map((col, j) =>
                                <td key={j} style={{backgroundColor:"pink", border:"1px solid black", width: "20px", height:"20px"}}>{col}</td>
                            )}
                        </tr>
                    )}
                    </tbody>
                </table>
            </div>
        )
    }
}

Here is the last component with my Snake game directions:

class Snake extends React.Component {
    constructor(props){
        super(props);

    }


    // poruszanie sie snakeeee'a
    handleKey = (e) => {
        const direction = e.keyCode;
        // console.log(direction);
        switch(e.keyCode) {
            case 37:
            console.log("LEFT");
                if(this.props.direction !== "RIGHT" && this.props.moving){
                    this.props.changeDirection("LEFT")
                }
                break;
            case 38:
            console.log("UP");
                if(this.props.direction !== "DOWN" && this.props.moving){
                    this.props.changeDirection("UP")
                }
                break;
            case 39:
            console.log("RIGHT");
                if(this.props.direction !== "LEFT" && this.props.moving){
                    this.props.changeDirection("RIGHT")
                }
                break;
            case 40:
            console.log("DOWN");
                if(this.props.direction !== "UP" && this.props.moving) {
                    this.props.changeDirection("DOWN")
                }
                break;
            default:
                break;
        }
    }

I’m not sure about this components, what I should delete, and what I should leave (I’m really confused with sending data to my array).

I feel I have to clear my code and start again.

Oh yeah, been there. I remember struggling to build my first React apps. I had to start from scratch several times. Structure is so important in these things and it takes a while to get an intuition for it.

It would be a lot easier to give you a good answer if I could see the complete code. Is this in a pen or in a git? You class Snake, for example, is incomplete.

Trying to look over it, I would have organized it a little differently. I would have the grid data in the state of App - you have it in Grid. I would put it in App and have the changeDirection function adjust it there. In this conception, Grid doesn’t need state, getting grid and dataArray passed to it as props.

A big issue with React is thinking about where state is going to be. Again, remember that each component has it’s own state and it isn’t shared unless explicitly passed.

Here is my grid component (another child), which finally I don’t know if shall I delete it and put everything on the Board?

That depends on what Board is. I think you might want to rename it to Header or something and then it makes sense for it to be a separate component.

I’m not sure about this components, what I should delete, and what I should leave (I’m really confused with sending data to my array).

Again, I think if you rename Board then you have a workable structure. You just have to decide where you want to keep state. To me, it is usually in the lowest common ancestor.

Here is a pen handling moves. It could probably be cleaner, but it will give you an idea. Notice that Controls has now idea about the mechanics of moving the character and neither does Grid. All the state and handlers are in App.

Let us know if you need more clarification.

Thank you Kevin so so much, I’m analyzing your code and everything becomes much more clear! I really appreciate your help. I’ll work on my game and come back again when I’m stuck on it.

1 Like