import { useEffect } from "react";
import { useRefState } from "utils";
export default function HomePage() {
const [mouseDownCounter, setMouseDownCounter] = useRefState(0);
useEffect(() => {
window.addEventListener("mousedown", () => {
setMouseDownCounter(mouseDownCounter + 1);
});
}, []);
return <div>{mouseDownCounter}</div>;
}
With react functional programing we got a problem of accessing latest react state inside addEventListener. “mouseDownCounter“ value will always to 0 inside addEventListener callback function, this can be solved by creating a custom hook that uses ref to store the state. Solution below.
import { useEffect } from "react";
import { useRefState } from "utils";
export default function HomePage() {
const [
mouseDownCounter,
setMouseDownCounter,
getMouseDownCounter,
] = useRefState(0);
useEffect(() => {
window.addEventListener("mousedown", () => {
setMouseDownCounter(getMouseDownCounter() + 1);
});
}, []);
return <div>{mouseDownCounter}</div>;
}
useRefState is same as useState, but has third parameter that exposes the current value of the state. To expose the current state we use react ref. Code below.
/**
* same as use state, but we get a third param to get current value. This will be useful while working with settimeout, eventHandlers, promises and axios api calls.
*/
export function useRefState<T>(
defaultValue: T
): [T, (updatedValue: T) => void, () => T] {
const ref = useRef(defaultValue);
const [state, setState] = useState(defaultValue);
function setStateFn(updatedValue: any) {
ref.current = updatedValue;
setState(updatedValue);
}
function getValueFn() {
return ref.current;
}
return [state, setStateFn, getValueFn];
}
Top comments (4)
@michaelsalim
yup that willl work for this specific case. But In case if we want to just get the updated mouseDownCounter and do actions based on the value, useRefState would be a better off solution.
you might think of
let updatedMouseDownCounter = '';
setState(mouseDownCounter => {
uodatedMouseDownCounter = mouseDownCounter;
return mouseDownCounter
}
But this will trigger a re-render. So useRefState is a better option to access updated state value in eventhandlers
@deltd3v
same like a useState, but you get a 3rd parameter, which exposes the current value that could be used inside eventhandlers.
For this specific case, you'll probably be better off using the following:
If you pass in a function, it will pass the current value on the parameter
Could you please show how you'd use this hook in a component ?