Search code examples
javascriptreactjskeyevent

When a key is pressed, the event occurs twice


When I press a key using keyEvent, then I call the function, it is below.

const GeneratedKey: FC<IGenerated> = (props) => {

    const [keyBoard, setKeyBoard] = useState("")
    const [arrayMovie, setArrayMovie] = useState<string[]>([])
    const idPage = props.idpage
    const nameMovie = data.results[idPage].title
    const [idLetter, setIdLetter] = useState<number>(0)
    const [indexArray, setIndexArray] = useState<number[]>([])
    const arrayNameMovie = nameMovie.split(" ").join("").split("");
    
    const getKey = (e: any) => {
        console.log("test")
        const key = e.key
        let count = 0
        for (let i = 65; i <= 90; i++) {
            if (key.toUpperCase() == String.fromCharCode(i)) {
                count = 1
            } else if (key.toLowerCase() == "backspace") {
                count = 10
            }
        }
        if (count == 1) {
            indexArray.sort(function (a: any, b: any) {
                return a - b;
            })
            arrayMovie.splice(indexArray[idLetter], 1, key)
            setIdLetter(idLetter + 1)
        } else if (count == 10) {
            if (idLetter >= 1) {
                setIdLetter(idLetter - 1)
                arrayMovie.splice(indexArray[idLetter], 1, "")
            }
        }
        setKeyBoard(key)
        document.removeEventListener("keydown", getKey);
    }

    useEffect(() => {
        for (let i = 3; i >= 0; i--) {
            const randomIndex = Math.floor(Math.random() * arrayNameMovie.length)
            arrayNameMovie.splice(randomIndex, 1, " ")
            indexArray.push(randomIndex)
        }
        setIdLetter(indexArray[0])
        setArrayMovie(arrayNameMovie)
    }, [])

    document.addEventListener("keydown", getKey)

    return (
        <div className="down__word">
            {arrayMovie.map((letter: any) =>
                <LettersView letters={letter} props={undefined} />
            )}
        </div>
    )
}

In fact, it should be called once, but it fires twice, as you can see from console.log(); How can I fix this, I can also show other files with code, but this is unlikely to help


Solution

  • This is due to your component may get rendered twice (due to change of props or any external reason). Moreover I think this is not the correct way to handle the event listener in FC. You should consider the useEffect for registration / un-registration of event listener.

    useEffect(() => {
      const handler = () => {};
      document.addEventListener('keydown', handler);
      return () => {
        document.removeEventListener('keydown', handler);
      }
    }, [deps]); // if you have any changing dependency else just remove the array to execute the UseEffect everytime.
    

    This will ensure that you have registered the event only once in your code.

    Refer https://reactjs.org/docs/hooks-effect.html