I know there are many questions about removeEventListener on stackoverflow, but none of the answers have worked for me.
I am also not sure if removeEventListener is the issue causing problem.
i wrote 2048 game clone, but with every arrow click eventListener fires 2 times more than previously (2,4,8,16...) so after around 10 clicks app stops working.
I spent hours trying to find the issue but cannot find it...
The entire app code is below, its written in react:
import "./Board.css"
import {useEffect, useState} from "react";
import {v4} from "uuid"
const Board = () => {
const [globalBoard, setGlobalBoard] = useState(null)
useEffect(()=>{
initializeGame()
},[])
useEffect(()=>{
const handleGame = (e, board) => {
if (e.key !== "ArrowUp" &&
e.key !== "ArrowDown" &&
e.key !== "ArrowLeft" &&
e.key !== "ArrowRight"
) return
if (e.key === "ArrowUp") {
//take all numbers up
for (let i = 0; i < 3; i ) {
for (let j = 0; j < 4; j ) {
let k = 0
while (board[i][j] === 0 && k < 3) {
if (i === 0) {
board[i][j] = board[i 1][j]
board[i 1][j] = board[i 2][j]
board[i 2][j] = board[i 3][j]
board[i 3][j] = 0
}
if (i === 1) {
board[i][j] = board[i 1][j]
board[i 1][j] = board[i 2][j]
board[i 2][j] = 0
}
if (i === 2) {
board[i][j] = board[i 1][j]
board[i 1][j] = 0
}
k
}
}
}
//summarize all numbers
for (let i = 0; i < 3; i ) {
for (let j = 0; j < 4; j ) {
if (board[i][j] !== 0 && board[i][j] === board[i 1][j]) {
board[i][j] *= 2
if (i === 0) {
board[i 1][j] = board[i 2][j]
board[i 2][j] = board[i 3][j]
board[i 3][j] = 0
}
if (i === 1) {
board[i 1][j] = board[i 2][j]
board[i 2][j] = 0
}
if (i === 2) {
board[i 1][j] = 0
}
}
}
}
}
if (e.key === "ArrowDown") {
//take all numbers down
for (let i = 3; i > 0; i--) {
for (let j = 0; j < 4; j ) {
let k = 0
while (board[i][j] === 0 && k < 3) {
if (i === 3) {
board[i][j] = board[i - 1][j]
board[i - 1][j] = board[i - 2][j]
board[i - 2][j] = board[i - 3][j]
board[i - 3][j] = 0
}
if (i === 2) {
board[i][j] = board[i - 1][j]
board[i - 1][j] = board[i - 2][j]
board[i - 2][j] = 0
}
if (i === 1) {
board[i][j] = board[i - 1][j]
board[i - 1][j] = 0
}
k
}
}
}
//summarize all numbers
for (let i = 3; i > 0; i--) {
for (let j = 0; j < 4; j ) {
if (board[i][j] !== 0 && board[i][j] === board[i - 1][j]) {
board[i][j] *= 2
if (i === 3) {
board[i - 1][j] = board[i - 2][j]
board[i - 2][j] = board[i - 3][j]
board[i - 3][j] = 0
}
if (i === 2) {
board[i - 1][j] = board[i - 2][j]
board[i - 2][j] = 0
}
if (i === 1) {
board[i - 1][j] = 0
}
}
}
}
}
if (e.key === "ArrowLeft") {
//take all numbers to the left
for (let i = 0; i < 4; i ) {
for (let j = 0; j < 3; j ) {
let k = 0
while (board[i][j] === 0 && k < 3) {
if (j === 0) {
board[i][j] = board[i][j 1]
board[i][j 1] = board[i][j 2]
board[i][j 2] = board[i][j 3]
board[i][j 3] = 0
}
if (j === 1) {
board[i][j] = board[i][j 1]
board[i][j 1] = board[i][j 2]
board[i][j 2] = 0
}
if (j === 2) {
board[i][j] = board[i][j 1]
board[i][j 1] = 0
}
k
}
}
}
//summarize all numbers
for (let i = 0; i < 4; i ) {
for (let j = 0; j < 3; j ) {
if (board[i][j] !== 0 && board[i][j] === board[i][j 1]) {
board[i][j] *= 2
if (j === 0) {
board[i][j 1] = board[i][j 2]
board[i][j 2] = board[i][j 3]
board[i][j 3] = 0
}
if (j === 1) {
board[i][j 1] = board[i][j 2]
board[i][j 2] = 0
}
if (j === 2) {
board[i][j 1] = 0
}
}
}
}
}
if (e.key === "ArrowRight") {
//take all numbers to the left
for (let i = 0; i < 4; i ) {
for (let j = 3; j > 0; j--) {
let k = 0
while (board[i][j] === 0 && k < 3) {
if (j === 3) {
board[i][j] = board[i][j - 1]
board[i][j - 1] = board[i][j - 2]
board[i][j - 2] = board[i][j - 3]
board[i][j - 3] = 0
}
if (j === 2) {
board[i][j] = board[i][j - 1]
board[i][j - 1] = board[i][j - 2]
board[i][j - 2] = 0
}
if (j === 1) {
board[i][j] = board[i][j - 1]
board[i][j - 1] = 0
}
k
}
}
}
//summarize all numbers
for (let i = 0; i < 4; i ) {
for (let j = 3; j > 0; j--) {
if (board[i][j] !== 0 && board[i][j] === board[i][j - 1]) {
board[i][j] *= 2
if (j === 3) {
board[i][j - 1] = board[i][j - 2]
board[i][j - 2] = board[i][j - 3]
board[i][j - 3] = 0
}
if (j === 2) {
board[i][j] = board[i][j - 1]
board[i][j - 1] = board[i][j - 2]
board[i][j - 2] = 0
}
if (j === 1) {
board[i][j] = board[i][j - 1]
board[i][j - 1] = 0
}
}
}
}
}
//check if previous board differs from the current one (if it does not, we don't want to add extra number)
console.log(globalBoard)
let arrayChanged = false
for (let i = 0; i < 4; i ) {
for (let j = 0; j < 4; j ) {
if (globalBoard[i][j] !== board[i][j]){
arrayChanged = true
}
}
}
if (arrayChanged){
//draw a spot on the board
let number1 = Math.floor(Math.random() * 4)
let number2 = Math.floor(Math.random() * 4)
//check if the spot is empty - does not contain a number
while (board[number1][number2] !==0){
number1 = Math.floor(Math.random() * 4)
number2 = Math.floor(Math.random() * 4)
}
//create a new number: 2 or 4 (with 80% chance that it will be 2) and place it in the selected spot
board[number1][number2] = (Math.floor(Math.random() * 10) >= 8) ? 4 : 2;
setGlobalBoard([...board])
}
}
if (globalBoard){
let board = [[...globalBoard[0]],[...globalBoard[1]],[...globalBoard[2]],[...globalBoard[3]]]
window.addEventListener("keydown",(e)=> handleGame(e,board))
}
return ()=> window.removeEventListener("keydown",handleGame)
},[globalBoard])
const initializeGame = () => {
let board = []
for (let i = 0; i < 4; i ) {
board.push([])
for (let j = 0; j < 4; j ){
board[i].push(0)
}
}
let randomNr1 = Math.floor(Math.random()*4)
let randomNr2 = Math.floor(Math.random()*4)
//push first number
board[randomNr1][randomNr2] = 2;
let newRandomNr1;
let newRandomNr2;
do {
newRandomNr1 = Math.floor(Math.random()*4)
newRandomNr2 = Math.floor(Math.random()*4)
}while (randomNr1===newRandomNr1 && randomNr2===newRandomNr2)
board[newRandomNr1][newRandomNr2] = (Math.floor(Math.random()*10) >= 8) ? 4 : 2
setGlobalBoard(board)
return board
}
return (
<div className="board">
{globalBoard && globalBoard.map((array)=>{
return array.map((el)=>{
return <div key={v4()} className="element">{el === 0 ? "" : el}</div>
})
})}
</div>
);
};
export default Board;
CodePudding user response:
Change to this
To delete a listener, you need to pass the same function to it as to create a listner.
We create an intermediate function beginHandleGame
and pass it to create a listner and delete it.
let board;
const beginHandleGame (e) => {
handleGame(e,board);
}
if (globalBoard){
board = [[...globalBoard[0]],[...globalBoard[1]],[...globalBoard[2]],[...globalBoard[3]]]
window.addEventListener("keydown", beginHandleGame);
}
return ()=> window.removeEventListener("keydown", beginHandleGame)
CodePudding user response:
You should pass the same handler to addEventListener and removeEventListener.
At first, you have created an event listener and passed the anonymous arrow function, after all, you remove that event and pass handlegame
function.
Your code should look like this.
const handler = (e) => {
//do something
}
window.addEventListener('keydown', handler)
//.....//
window.removeEventListener('keydown', handler)