I want to show notification message after 4 seconds when some state is invalid. But if during that 4 seconds it has changed and is valid now - I want to put condition in setTimeout
that would check it. But the problem is that it still uses the first state value, not the changed one. One of my assumptions to fix it was making setState
in the line before synchronous, but don't know how. Maybe any other ways to fix it?
useEffect(async () => {
try {
const snippetIndexResponse = await getSnippetIndex(
//some params
);
if (snippetIndexResponse !== -1) {
setSnippetIndex(snippetIndexResponse);
} else {
setSnippetIndex(null)
setTimeout(() => {
console.log(snippetIndex) <-- it logs only first state, instead wanted null
if(!snippetIndex) {
openNotificationWithIcon(
"error",
"Invalid snippet selection",
"Snippet slice shouldn't tear code blocks. Please, try again."
);
}
}, 4000)
}
} catch (err) {
setSnippetIndex(null);
openNotificationWithIcon("error", err.name, err.message);
}
}, [beginRow, endRow]);
CodePudding user response:
I think you could make the notification UI a component and pass the state in as a parameter. If the state changes the component will be destroyed and recreated. And you can add the 4 second timer in useEffect() as well as cancel it in the 'return' of useEffect. If the timer fires, update some visibility flag.
Live typing this - so may contain some syntax errors...
cost myAlert = (isLoading) => {
const [isVisible, setIsVisible] = setIsVisible(false)
useEffect(()=>{
const timerId = setTimer, setIsVisible(true) when it goes off
return ()=>{cancelTimer(timerId)}
}, [isLoading, setIsVisible])
if (!isLoading && !isVisible) return null
if (isVisible) return (
<>
// your ui
</>
)
}
You may want to useCallback on setTimer so it won't cause useEffect to fire if isLoading changes -- but I think this should get you close to the solution.
CodePudding user response:
First You can not call useEffect callback as async method.
Second for your purpose you can act as below:
let timeoutId = null;
useEffect(() => {
(async () => {
if (timeoutId) {
clearTimeout(timeoutId);
}
try {
const snippetIndexResponse = await getSnippetIndex(
//some params
);
if (snippetIndexResponse !== -1) {
setSnippetIndex(snippetIndexResponse);
} else {
setSnippetIndex(null)
timeoutId = setTimeout(() => {
console.log(snippetIndex) <-- it logs only first state, instead wanted null
if(!snippetIndex) {
openNotificationWithIcon(
"error",
"Invalid snippet selection",
"Snippet slice shouldn't tear code blocks. Please, try again."
);
}
}, 4000)
}
} catch (err) {
setSnippetIndex(null);
openNotificationWithIcon("error", err.name, err.message);
}
})();
}, [beginRow, endRow]);