Reputation: 327
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?
Upvotes: 0
Views: 29
Reputation: 63524
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>
Upvotes: 1
Reputation: 1
Hey I Just made few changes to your code to make it work on my local.
All changes have been in the screen.js files. The problem is how you update states with 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;
This part is more optimised, handles desubscriptions and using the React Way
Upvotes: 0
Reputation: 41387
use the spread operator to fire the useState changes
setPlayerCoordinate((prev) => {
prev.x -= 1;
return {...prev};
})
Upvotes: 1