FINAL EDIT: I solved it, check my answer below
EDIT: So, the problem boils down to this. How can i change the value of a state from inside an eventListener? I have tried the things below, as well as the advice of the people below.
I can change it no problem from outside of an event listener but for this usecase it is quite important that it changes through an event
I have a boolean state variable whose job is to re-render an element.
In the use effect hook it works as expected, whenever one of the deps changes, it flips and re-renders the component.
The thing is, i need it to be fired with an event listener and it just does not.
<EDIT>
: Sorry for the confusion, i am still learning.
I changed the code a bit.
const transition = () => {
console.log("running callback");
const content = document.getElementById("content");
const greeting = document.querySelector(".fadeInAndOut");
greeting?.addEventListener(
"animationend",
() => {
console.log("event fired");
greeting?.classList.remove("fadeInAndOut");
greeting?.setAttribute("style", "opacity: 0");
content?.classList.add("fadeIn");
console.log(`1 ${reset}`);
setReset(!reset);
console.log(`2 ${reset}`);
cleanUp();
greeting?.removeEventListener("animationend", () => {
console.log("removed2");
});
},
{ once: true }
);
};
useEffect(() => {
transition();
}, []);
This is the effect that people have been asking to see. It flips the reset value when needed but the flipping in the event listener will not work even now
useEffect(() => {
setReset(!reset);
}, [page, lang]);
</EDIT>
Here is the code:
const transition = useCallback(() => {
console.log("running callback");
const content = document.getElementById("content");
const greeting = document.querySelector(".fadeInAndOut");
greeting?.addEventListener(
"animationend",
() => {
console.log("event fired");
greeting?.classList.remove("fadeInAndOut");
greeting?.setAttribute("style", "opacity: 0");
content?.classList.add("fadeIn");
console.log(`1 ${reset}`);
setReset(!reset);
console.log(`2 ${reset}`);
cleanUp();
},
{ once: true }
);
}, []);
When i console log it in the useEffect case, i get true,false,true etc…
console.log from the useCallback always returns the same value
I need this to only happen on first page load, hence the useCallback with no deps.
EDIT: changing the use callback to include "reset" in the deps does not solve the issue and also causes it to fire again. changing the setReset to
setReset(reset => !reset)
also does not change the state
Bonus question: I know react will fire the useCallback twice when developing but even though the event listener has the "once: true" option it gets added and therefore fired twice. Is something wrong with my declaration of it?
2
Answers
So, i am not very smart. As the good people commented i never needed to use the useCallback hook. Now,i cannot get an event listener added to the element to fire a setState. So what i did was use this:
and here are the functions
React’s
useCallback
works based onreferences
, meaning whenuseCallback
returns a function, it memoize the definition of the function.Your initial value of
reset
state, will be taken in function’s definition, due to your dependency foruseCallback
being[]
.To support your case, just update it to,
useCallback(() => { ... }, [reset]);