react-native: Errors thrown in useEffect cleanup functions result in `Internal React error`
Description
When an app includes a functional component which calls React.useEffect with a cleanup callback, and that callback throws an error when called, the following is produced in the console:
ERROR Warning: Internal React error: Attempted to capture a commit phase error inside a detached tree. This indicates a bug in React. Likely causes include deleting the same fiber more than once, committing an already-finished tree, or an inconsistent return pointer.
The error is not detectable otherwise: the error boundary component does not catch it, nor does installing a global handler with ErrorUtils.setGlobalHandler().
This is on React Native 0.66.3 and React 17.0.2. I’ve also checked React 17.0.1 (no difference in behaviour), and RN 0.65.0 (the one that we currently use in production) which also gobbles up the error, but silently, without producing any message in the console.
The app seemingly continues to work after the error occurs.
I don’t think this is an actual React bug (as opposed to React Native), because on web, the error appears in the browser console, as expected.
I checked only the debug build behaviour, not the release one. It may be the case that in release builds the error sometimes does bubble up to the global error handler (if set), because we’re seeing prod exceptions that are likely to be related to this issue. For the record, what causes this for us is this issue in react-navigation, exacerbated by the fact that they had moved removing listeners to a useEffects cleanup function.
Version
0.66.3
Output of react-native info
System:
OS: macOS 11.4
CPU: (6) x64 Intel(R) Core(TM) i5-8500B CPU @ 3.00GHz
Memory: 1.97 GB / 32.00 GB
Shell: 5.8 - /bin/zsh
Binaries:
Node: 15.3.0 - ~/.nvm/versions/node/v15.3.0/bin/node
Yarn: 1.22.15 - /usr/local/bin/yarn
npm: 7.0.14 - ~/.nvm/versions/node/v15.3.0/bin/npm
Watchman: 2021.10.04.00 - /usr/local/bin/watchman
Managers:
CocoaPods: 1.11.2 - /Users/nathell/.gem/bin/pod
SDKs:
iOS SDK:
Platforms: iOS 14.5, DriverKit 20.4, macOS 11.3, tvOS 14.5, watchOS 7.4
Android SDK: Not Found
IDEs:
Android Studio: 3.6 AI-192.7142.36.36.6392135
Xcode: 12.5/12E262 - /usr/bin/xcodebuild
Languages:
Java: 11.0.7 - /usr/bin/javac
npmPackages:
@react-native-community/cli: Not Found
react: 17.0.2 => 17.0.2
react-native: 0.66.3 => 0.66.3
react-native-macos: Not Found
npmGlobalPackages:
*react-native*: Not Found
Steps to reproduce
-
Create a RN app with
react-native init myapp. -
Edit
App.jsto read:
import React from 'react';
import { Text, TouchableOpacity, View, SafeAreaView } from 'react-native';
const Hello = () => {
React.useEffect(() => {
console.log("mount");
return () => {
console.log("cleanup");
throw new Error("KABOOM!");
console.log("cleanup 2");
};
}, []);
return <Text>Hello!</Text>;
}
const App = () => {
const [shown, show] = React.useState(false);
const onPress = () => show(!shown);
return (
<SafeAreaView>
{ shown ? <Hello /> : null }
<TouchableOpacity onPress={onPress}>
<Text>Touch me</Text>
</TouchableOpacity>
</SafeAreaView>
);
};
export default App;
- Run the resulting app (on either iOS or Android) and tap
Touch metwice.
Expected result (in the react-native start output):
LOG mount
LOG cleanup
ERROR Kaboom!
Actual result:
LOG mount
LOG cleanup
ERROR Warning: Internal React error: Attempted to capture a commit phase error inside a detached tree. This indicates a bug in React. Likely causes include deleting the same fiber more than once, committing an already-finished tree, or an inconsistent return pointer.
Snack, code example, screenshot, or link to a repository
No response
About this issue
- Original URL
- State: open
- Created 3 years ago
- Reactions: 9
- Comments: 42
I’ve fixed that by changing my listeners, with the new React Native version we need to change them.
Upgrading from react-navigation 5 to react-navigation 6 solved the problem for me.
The return in a
useEffectshould be a function: https://reactjs.org/docs/hooks-effect.html#:~:text=Effects with Cleanup. If you’re getting an error, check what you’re returning in theuseEffectI had already updated the listeners to: ⚠️⚠️⚠️⚠️⚠️⚠️
But following @colaquecez suggestion worked great, problem solved. 🚀😁🎉😉👏🎊
Thanks!
Check if any async is used inside useEffect hook and remove it. Worked for me
I got roughly the same issue here, with react base
@jarapamikaella @trehman82 and any future commenters. Please read the comments already left in this issue: https://github.com/facebook/react-native/issues/32673?notification_referrer_id=NT_kwDOAsIbh7MyNzUwOTI2MDc0OjQ2Mjc1NDYz#issuecomment-1406970645.
There are no solutions/updates posted because as far as I can tell this is a problem the way you are using
useEffectso you need to debug your own code.@Degan90 and for anyone else in the future, it’s not an RN problem as far as I can tell. The problem is something to do with your code in the useEffect. Previous solutions from comments above:
Your problem might be different from the ones listed above but you’ll have to debug the code yourself to figure out the exact problem. I would start by reading the RN doc or searching up the error to find other mistakes when using
useEffectthat might be similar to yoursyap me too , have this issue , anyone can solve it ?
I also have this issue…
@satya164 Do you have any solution regarding this ?
Hello,
You need:
so you need to return a cleanup function in any case even if you don’t need it
<ApiProvider api={userApi} setupListeners={false}>{children}</ApiProvider>for react native v0.72.3 I fixed by adding setupListeners={false} it worked for me.I thought the solution is that you guys, when calling event Listener … i.e–>> useEffect (e => { e.addEventListener} //you should do this… const any_name = e => { e.addEventListener}
// and for clearing the event you should this! return ()=> { any_name.remove(); },[] )
Thank you so much! migrating from RN 0.64 -> 0.71 and a lot of different things discovered.
We just upgraded React Native from 0.69.7 to 0.71.3 and we started getting this in tons of Testing Library tests. Started by removing all the useEffects in a component to test a simple render test, and was still getting the error. So I stripped the component of anything besides a View inside a SafeAreaView and still getting the error in the test.
So now the Tree is simply this:
Theres no error in the tests if I render the Component without the Navigator stack, so seems to be related to @react-navigation
same issue facing here