I am trying to trigger a slider next and previous events on
- next and previous click or
- Left and Right Arrow Click
OnClick events are working as expected. But KeyDown handler not working as expected.
It is working fine on first keypress, like incrementing or decrementing by 1.
But after that, it either goes to -1 or +1.
I guess, I am missing some basic concept. Pls guide me where I am missing.
You can test here:
https://codesandbox.io/embed/zen-goodall-35f17?fontsize=14&hidenavigation=1&theme=dark
import React, {useState, useEffect} from "react"
function App(){
const [curImage, move] = useState(0);
const handleKeypress = (e) => {
console.log("keydown", e.keyCode);
if (e.keyCode === 37) {
leftClick();
} else if (e.keyCode === 39) {
rightClick();
}
};
/* eslint-disable */
useEffect(() => {
document.addEventListener("keydown", handleKeypress);
return () => document.removeEventListener("keydown", handleKeypress);
}, []);
/* eslint-enable */
function leftClick() {
move(curImage - 1);
}
function rightClick() {
move(curImage + 1);
}
return(
<>
<button onClick={leftClick}>prev</button>
{" "}
{curImage}
{" "}
<button onClick={rightClick}>next</button>
</>
)
}
export default App;
>Solution :
You can use functional state update to access the previous state and useCallback hook for memoization so that useEffect won’t trigger unnecessarily.
import React, { useState, useEffect, useCallback } from "react";
function App() {
const [curr, setCurr] = useState(0);
const leftClick = useCallback(() => {
setCurr((prevCurr) => prevCurr - 1);
}, []);
const rightClick = useCallback(() => {
setCurr((prevCurr) => prevCurr + 1);
}, []);
const handleKeypress = useCallback(
(e) => {
if (e.keyCode === 37) {
leftClick();
} else if (e.keyCode === 39) {
rightClick();
}
},
[leftClick, rightClick]
);
useEffect(() => {
document.addEventListener("keydown", handleKeypress);
return () => document.removeEventListener("keydown", handleKeypress);
}, [handleKeypress]);
return (
<>
<button onClick={leftClick}>prev</button>
{" "}
{curr}
{" "}
<button onClick={rightClick}>next</button>
</>
);
}