简体   繁体   中英

getting different output when calling function draw directly? React Tetris

I have a draw() function which updates my state.board . When i call it through game() function with setTimeout , I am getting expected output. But when I try to call it directly, output is different. It looks like in the second case everything works as it should up to this.setState({ board: newBoard } line. My state.board is not being updated. Can you please tell me why?

class App extends Component {
    constructor(props) {
        super(props)

        this.state = {
            board: [
                [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
            ],
            piece:
                [
                    [1, 0, 0],
                    [1, 0, 0],
                    [1, 1, 1]
                ],
        }
    }
    game = () => {
        this.gameID = setTimeout(this.draw, 10);
    }
    draw = () => this.state.piece.forEach((row, yPos) =>
        row.forEach((blockColor, xPos) => {
            if (blockColor !== 0) {
                const newBoard = this.state.board.map((row, y) => row.map((value, x) => {
                    if ((y === yPos && x === xPos && blockColor !== 0)) { return value = blockColor }
                    else { return value }
                }));
                this.setState({ board: newBoard }, console.log("newBoard ", newBoard, "   state.board ", this.state.board));
            }
        }))
render() {
    return (
        <Layout>
            <div className="game-area">
                <Board board={this.state.board} />

            </div>
            <button type="button" onClick={this.game}>Start</button>

            <button type="button" onClick={this.draw}>step</button>

        </Layout>
    )
}
}

export default App;

What I get by calling game() (expected)

0: (10) [1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
1: (10) [1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
2: (10) [1, 1, 0, 0, 0, 0, 0, 0, 0, 0]
3: (10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
4: (10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
5: (10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
6: (10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
7: (10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
8: (10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
9: (10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
10: (10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
11: (10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
12: (10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
13: (10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
14: (10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
15: (10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
16: (10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
17: (10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
18: (10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
19: (10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0

What I get by calling draw() directly:

0: (10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
1: (10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
2: (10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
3: (10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
4: (10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
5: (10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
6: (10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
7: (10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
8: (10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
9: (10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
10: (10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
11: (10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
12: (10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
13: (10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
14: (10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
15: (10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
16: (10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
17: (10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
18: (10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
19: (10) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

My Board component

import React from 'react';
class Board extends React.Component{
  render(){
  return (
   <div>
     {this.props.board.map((row,y)=>
       row.map((value,x)=>{

         const style ={
          top: (y*40) , left: (x*40),
          backgroundColor: 'red'
         }
         if(value===0){style.backgroundColor = 'blue'}
         else if (value ===1){style.backgroundColor = 'green'}
         else if (value ===2){style.backgroundColor = 'yellow'}
         //console.log("row: "+row+"x: "+x+"y: "+y);
         return(<div className = "block" style = {style}></div>)
       })
     )}
   </div>
  );
}}
export default Board;

Layout.js

    import React from 'react';

import Aux from '../hoc/Aux';

const layout = (props) => (
    <Aux>
    <div>Toolbar, SidePanel</div>
    <main>
        {props.children}
    </main>
    </Aux>

);

export default layout;

setState may run asynchronously. This means that this.state may not immediately be updated after you call this.setState . Thus, referring to this.state after updating is dangerous, because you'll be referring once again to pre-updated data within each loop iteration. Also, setState provokes an update, and you don't want to kick off multiple updates in response to one event.

I'd recommend you only do one setState operation, something like this:

draw = () => {
  let newBoard = this.state.board;
  this.state.piece.forEach((row, yPos) => {
    row.forEach((blockColor, xPos) => {
      if (blockColor !== 0) {
        newBoard = newBoard.map((row, y) => row.map((value, x) => {
          if ((y === yPos && x === xPos && blockColor !== 0)) {
            return value = blockColor 
          } else { 
            return value 
          }
        }));
      }
    })
  });

  this.setState({
    board: newBoard
  }, () => { 
    console.log("newBoard ", newBoard, "   state.board ", this.state.board) 
  });
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM