Search code examples
javascriptreactjsreact-hookscomponents

properties that have the values of a state is not changed when the state is updated


I have the component Player. It returns a div with an image. It has the properties x and y. These properties are passed as the left and top values of the div inside Player. Outside the component Player, I have the state playerCoordinate. It is passed as the values for x and y properties of Player.
Whenever the left arrow key is pressed, playerCoordinate is updated. I see that playerCoordinate is updated well when the left arrow key is pressed. However, despite the fact that playerCoordinate is updated, it does not update the values for x and y.

Here are the codes:
Screen.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

Player.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

I am not quite new to React and could not find any appropriate solution for the issue. What is possibly wrong here?


Solution

  • use the spread operator to fire the useState changes

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