gluestack-ui
gluestack-ui copied to clipboard
Using toast as useEffect dependency causes infinite calls.
Description
toast causes useEffect to run infinitely if used as dependency, it apparently shouldn't do that
CodeSandbox/Snack link
No response
Steps to reproduce
Inside a component
-
const toast = useToast()
-
useEffect(()=>{ toast.show(...) },[toast,error])
-
That's it
gluestack-ui Version
1.1.8
Platform
- [ ] Expo
- [X] React Native CLI
- [ ] Next
- [ ] Web
- [X] Android
- [X] iOS
Other Platform
No response
Additional Information
No response
@endrits079 Thanks for reporting this. We'll have a look.
Hey @endrits079, this is an expected behaviour as useToast hook internally is accessing some context values. Calling toast.show() inside the useEffect hook is somehow causing the toast context values to update, which then creates a new toast object.
Since you have added toast in the dependency array, useEffect sees a new toast object, re-runs, and calls toast.show again. This cycle repeats, causing the infinite loop.
This is how our useToast hook internally works:
const useToast = () => {
const { AnimationWrapper,
AnimatePresence,
setToast,
hideAll,
isActive,
hideToast,
} = React.useContext(ToastContext);
AnimatePresence.current = StyledAnimatePresence;
AnimationWrapper.current = StyledAnimationWrapper;
const toast = useMemo(
() => ({
show: setToast,
close: hideToast,
closeAll: hideAll,
isActive,
}),
[setToast, hideAll, isActive, hideToast]
);
return toast;
};
A possible solution for this is to empty the dependency array. If you only want the toast to show once on initial render, change the useEffect dependency array to []. This prevents re-runs on subsequent changes to toast.
Hey @endrits079 , we are closing this issue for now, please feel free to reopen the issue if you are still facing it/ having any queries about it.
Hey @endrits079, this is an expected behaviour as useToast hook internally is accessing some context values. Calling toast.show() inside the useEffect hook is somehow causing the toast context values to update, which then creates a new toast object.
Since you have added toast in the dependency array, useEffect sees a new toast object, re-runs, and calls toast.show again. This cycle repeats, causing the infinite loop.
This is how our useToast hook internally works:
const useToast = () => { const { AnimationWrapper, AnimatePresence, setToast, hideAll, isActive, hideToast, } = React.useContext(ToastContext); AnimatePresence.current = StyledAnimatePresence; AnimationWrapper.current = StyledAnimationWrapper; const toast = useMemo( () => ({ show: setToast, close: hideToast, closeAll: hideAll, isActive, }), [setToast, hideAll, isActive, hideToast] ); return toast; };A possible solution for this is to empty the dependency array. If you only want the toast to show once on initial render, change the useEffect dependency array to []. This prevents re-runs on subsequent changes to toast.
Hey so this design is insane lol -- why are you re-creating the toast object every time isActive changes? Quite literally the only toast library I've ever seen do this, and definitely not expected behavior for any developer building on Gluestack (you'll just get infinite loops if you try to show toasts in a useEffect, like the OP)