【问题标题】:React setState function from useState not updaing state value从 useState 反应 setState 函数不更新状态值
【发布时间】:2020-12-13 22:01:10
【问题描述】:

从下面的代码中,虽然我确实使用较新的数组调用 setSnake 函数,但蛇变量 ( state var ) 在第一次按键后不会更新... 在进一步按键时,snake 的值始终为 {x:0, y:1 }( 如果您按右箭头键

知道为什么吗?

const  SnakeBoard = () => {
    
    const width=10;
    const height=10;

    let initialRows = []
    for(let i=0;i<10;i++){
        initialRows.push([])
       for(let j=0;j<10;j++)
       {
        if( i==0 && j == 0)
             initialRows[i].push('snake')
        else
            initialRows[i].push('blank')
       }
    }

    const [rows,  setRows]  = useState(initialRows)
    const [snake, setSnake] = useState([{x:0,y:0}])
    
    const displaySnake = ()=>{
        
        const newRows = rows;
        snake.forEach(cell=>{
            newRows[cell.x][cell.y] = 'snake'
        })

        // console.log('newRows')  
        // console.log(newRows)  
        setRows(newRows);
    }

    const changeDirectionWithKeys = (e)=>{
        e.preventDefault()
        const {key} = e  
        console.log(key)  
        moveSnake(key)
        
    }

    const moveSnake =(key) =>{
        const newSnake = []

        switch(key){

            case 'ArrowRight':
                newSnake.push({x: snake[0].x, y: snake[0].y + 1})
                break;

            case 'ArrowLeft':
                newSnake.push({x: snake[0].x, y:snake[0].y - 1})
                break;

            case 'ArrowUp':
                newSnake.push({x: snake[0].x - 1, y:snake[0].y})
                break;

            case 'ArrowDown':
                newSnake.push({x:snake[0].x + 1, y: snake[0].y})
                break;
        }


        if(snake.length !==1){
        snake.forEach(cell=> {
            newSnake.push(cell);
        })    
        }

        console.log(newSnake)
        console.log(snake)
        setSnake(...newSnake)
        displaySnake()
    }

    useEffect(() => {
        
        window.addEventListener('keyup',changeDirectionWithKeys)

        return () => {
            window.removeEventListener('keyup',changeDirectionWithKeys)
        }
    }, [])

    const diplayRows = rows.map( (row,index) =>       
        <li> 
            {row.map((e,ind)=>{
                switch(e){
                    case 'blank':                     
                    return <span>{index} - {ind} |</span> ;//<img src={Blank} alt="blank"></img>

                    case 'snake': 
                    return <span>{index} - {ind} |</span> ;//<img src={Snake} alt="snake"></img>
                }

            })}
        </li>       
            
    )

   

    return (
        <div>
            <UL>
                {diplayRows}
            </UL>           
        </div>
    )
}

export default SnakeBoard

【问题讨论】:

  • 你正在使用 React,那么你为什么要改变现有的状态?永远不要在 React 中改变状态
  • 你能创建一个 fiddle/sn-p 吗?
  • 尝试从 setSnake(...newSnake) 中删除扩展运算符 (...)。所以把它改成 setSnake(newSnake)。

标签: reactjs use-state


【解决方案1】:

我修复了您的代码(方向、更新),并进行了一些重构。 它也不完美,但更容易。

const SnakeBoard = () => {
  const [rows, setRows] = useState([]);
  const [snake, setSnake] = useState([{ x: 0, y: 0 }, { x: 1, y: 0 }]);

  useEffect(()=> {
    const width = 10;
    const height = 10;
    let initialRows = [];
    for (let i = 0; i < height; i++) {
      initialRows.push("blank ".repeat(width).trim().split(' '));
    }
    for (let i = 0; i < snake.length; i++) { 
      initialRows[snake[i].y][snake[i].x] ="snake";
    }
    setRows(initialRows)
  }, [snake])

  useEffect(() => {
    const changeDirectionWithKeys = (e) => {
      e.preventDefault();
      const { key } = e;
      // cut tail and push new head
      const [tail, ...newSnake] = snake.length > 1 ? snake : [null, ...snake]  ;
      const head = snake[snake.length-1]
        switch (key) {
        case "ArrowRight":
          newSnake.push({ x: head.x + 1 , y: head.y }); // fix
          break;
        case "ArrowLeft":
          newSnake.push({ x: head.x - 1 , y: head.y }); // fix
          break;
        case "ArrowUp":
          newSnake.push({ x: head.x, y: head.y - 1 }); // fix
          break;
        case "ArrowDown":
          newSnake.push({ x: head.x, y: head.y + 1  }); // fix
          break;
        default:
          break;  
      }
      setSnake(newSnake);
    };

    window.addEventListener("keydown", changeDirectionWithKeys);
    return () => {
      window.removeEventListener("keydown", changeDirectionWithKeys);
    };
  }, [snake]);

  const diplayRows = rows.map((row, index) => (
    <li key={index}>
      {row.map((e, ind) => {
        let cell = null
        switch (e) {
          case "blank":
            cell = <span key={ind}> .|</span>;
            break;
          case "snake":
            cell = <span key={ind}> s|</span>;
            break;
          default:
            break;  
        }
        return cell;
      })}
    </li>
  ));

  return (
    <div>
      <ul>
        {diplayRows}
      </ul>
    </div>
  );
};

export default SnakeBoard;

【讨论】:

  • @Daniel 它运行良好。您能否解释一下为什么将 initiaRows 和 changeDirectionWithKeys 放入 useEffect 可以解决这个问题?
  • 我的初始代码中的错误是什么?
  • 正如CertainPerformance 和Jordan Maduro 昨天所写的那样1) 改变现有状态(它不再调用render!!)2) setSnake(...newSnake);必须是 setSnake(newSnake); 3) moveSnake 不会删除尾巴,因为 displaySnake 只是添加了蛇 4) 干净的代码))
  • 谢谢丹尼尔...我学到了一个新东西:-) ..实际上这条线正在改变状态 const newRows = rows;
猜你喜欢
  • 2023-04-02
  • 2021-01-14
  • 2021-01-28
  • 2021-06-02
  • 2018-12-08
相关资源
最近更新 更多