reactjs 具有状态值的属性在状态更新时不会更改

qqrboqgw  于 2022-12-22  发布在  React
关注(0)|答案(3)|浏览(236)

我有一个组件Player,它返回一个带有图像的div,它有属性xy,这些属性在Player内部作为div的左值和顶值传递,在Player组件外部,我有状态playerCoordinate,它作为Playerxy属性值传递。
只要按下左箭头键,playerCoordinate就会更新,我看到按下左箭头键时playerCoordinate更新得很好,但是尽管playerCoordinate更新了,但它并没有更新xy的值。
下面是代码:

屏幕.js

import { useState, useEffect } from 'react'
import styles from './ScreenStyles'

import ScriptDisplayer from '../ScriptDisplayer/ScriptDisplayer';
import Player from '../Player/Player'

function Screen() {
  const [playerCoordinate, setPlayerCoordinate] = useState({x: 641, y: 258})

  function handleUserKeyPress(event) {
    if (event.code === 'ArrowLeft') {
      console.log(event, playerCoordinate)
      setPlayerCoordinate((prev) => {
        prev.x -= 1;
        return prev;
      })
    }
  }

  useEffect(() => {
    window.addEventListener('keydown', handleUserKeyPress)
  }, [playerCoordinate])

  return (
  <>
    <div id='screen' style={styles.screen}>
      <ScriptDisplayer />
      <Player x={playerCoordinate.x} y={playerCoordinate.y} />
    </div>
  </>
  ); 
}

export default Screen

播放器.js

import playerGif from '../../assets/player.gif'

const styles = {
  playerGif: {
    height: 70,
    width: 70,
  }
}

function Player(props) {
  console.log('playerX: ', props.x, 'playerY: ', props.y)
  return(
    <div id='player' style={{position: 'absolute', left: `${props.x}px`, top: `${props.y}px`}}>
      <img id='playerGif' src={playerGif} style={styles.playerGif} />
    </div>
  );
}

export default Player

我对React并不是很陌生,找不到任何合适的解决方案。这里可能出了什么问题?

wb1gzix0

wb1gzix01#

使用spread运算符触发useState更改

setPlayerCoordinate((prev) => {
    prev.x -= 1;
    return {...prev};
  })
b5buobof

b5buobof2#

1.您需要返回一个新对象以识别状态更改。请使用spread syntax从以前的对象创建一个新对象,然后更新所需的属性。
1.不需要在每次状态更改时添加侦听器。使用空依赖项数组表示只希望在装入组件时添加一次侦听器。
1.然后,您应该添加一个cleanup函数,以便在卸载组件时删除侦听器。

const { useEffect, useState } = React;

function Screen() {
  
  const [playerCoordinate, setPlayerCoordinate] = useState({x: 641, y: 258});

  function handleUserKeyPress(event) {
    if (event.code === 'ArrowLeft') {
      setPlayerCoordinate(prev => {
        return { ...prev, x: prev.x - 1 };
      });
    }
  }

  useEffect(() => {
    window.addEventListener('keydown', handleUserKeyPress);
    return () => {
      window.removeEventListener('keydown', handleUserKeyPress);
    }
  }, []);

  return (
    <div id="screen">
      <Player
        x={playerCoordinate.x}
        y={playerCoordinate.y}
      />
    </div>
  ); 

}

function Player(props) {
  console.log('playerX: ', props.x, 'playerY: ', props.y);
  return (
    <div></div>
  );
}

ReactDOM.render(
  <Screen />,
  document.getElementById('react')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="react"></div>
tzdcorbm

tzdcorbm3#

嘿我只是对你的代码做了些修改让它能在我的本地运行。
所有更改都在screen.js文件中,问题是如何使用setPlayerCoordinate更新状态。

function Screen() {
  const [playerCoordinate, setPlayerCoordinate] = useState({ x: 641, y: 258 });

  useEffect(() => {
    const handleUserKeyPress = (event) => {
      if (event.code === "ArrowLeft") {
        setPlayerCoordinate((prev) => {
          return {
            ...prev,
            x: prev.x - 1
          };
        });
      }
    };
    window.addEventListener("keydown", handleUserKeyPress);
    return () => window.removeEventListener("keydown", handleUserKeyPress);
  }, []);

  return (
    <>
      <div id="screen">
        <Player x={playerCoordinate.x} y={playerCoordinate.y} />
      </div>
    </>
  );
}

export default Screen;

此部分更加优化,处理取消订阅和使用React Way

相关问题