@praveen your Some return value looks weird… you need to run Js.Global.clearTimeout in your cleanup to prevent the callback to be run when the component has been unmounted.
@react.component
let make = () => {
let (shouldShowSuccess, setShouldShowSuccess) = React.useState(_ => true)
React.useEffect1(() => {
if shouldShowSuccess {
let timeoutId = Js.Global.setTimeout(
() => setShouldShowSuccess(_prev => false),
3000,
)
Some(
() => {
Js.Global.clearTimeout(timeoutId)
},
)
} else {
None
}
}, [shouldShowSuccess])
<div />
}
I have used this function inside useEffect1. This function is actually returning another function that clears the timeout. I pass this returned function directly into Some. So returned function will be invoked on cleanup.
So what I have done is the same thing that you have written.
Similar to @praveen ended up creating a util in our codebase to create a timer that returns a cleanup function too:
module Timer = {
@ocaml.doc("
* Create a timeout that plays nicely with hooks like useEffect.
* Takes a function to call and int of ms to wait before calling the f func
* Returns a callback to clear the timeout but will only fire once otherwise
* results in noop
*
* @example
*
* React.useEffect0(() => {
Some(Hooks.Effects.Timer.make(() => Js.Console.log(\"hi\"), 1000))
})
")
let make = (f, ms) => {
let timer = Js.Global.setTimeout(f, ms)
() => Js.Global.clearTimeout(timer)
}
}
Which can be used like:
React.useEffect1(() => {
if partyStarted {
Some(Utils.Timer.make(
() => Js.log("Party has ended. You don't have to go home, but you can't stay here."),
3000
))
} else {
None
}
}, [partyStarted])