Skip to content

Commit

Permalink
- Fix BackHandle callback undefined cause crash issue (#48388)
Browse files Browse the repository at this point in the history
Summary:
### Error message:
we got an error
```
t[n] is not a function. (In 't[n]()', 't[n]' is undefined) \n <unknown> (index.bundle:317:168:317)
```
 it related the BackHandle execute handle function.

### Investigation result
our project has screen files`App.tsx`, `Dashboard.tsx`, and `Profile.tsx`.
When launching the app, the screen order is `App.tsx` -> `Dashboard.tsx`, then user can switch to `Profile.tsx`
For `App.tsx` and `Dashboard.tsx`, we just prevent the hardware button action use `usePreventHardwareBackPressEffect()` in the first line of screen code.
```js
export const useHardwareBackPressEffect = (goBack?: () => boolean): void => {
  useEffect(() => {
    if (goBack) {
      BackHandler.addEventListener("hardwareBackPress", goBack);
      return () => {
        BackHandler.removeEventListener("hardwareBackPress", goBack);
      };
    }
    return undefined;
  }, [ goBack ]);
};
export const usePreventHardwareBackPressEffect = (): void => useHardwareBackPressEffect(() => true);
```
currently, `_backPressSubscriptions ` has 2 callback functions.
then user switch to `Profile.tsx` screen, and has the below code for hardwareback button and the second doesn't `return true`:
```js
// first one
usePreventHardwareBackPressEffect();
...

// second one
useEffect(() => {
  const backButtonListener = BackHandler.addEventListener(
    "hardwareBackPress",
    () => navigate(Navigation.Login);
  );
  return () => backButtonListener.remove();
});
```
currently, `_backPressSubscriptions ` has 4 callback functions, include previous 2 and new 2 of `Profile.tsx`.
When the user press hardwareback button, it will navigate to the login screen, so the issue occurs:
the latest callback will be executed first, then the navigation will let the screen unmount, which will destroy the effect, so the code removing 2 hardwareBackPress callback of `Profile.tsx` by executed
```js
return () => {
        BackHandler.removeEventListener("hardwareBackPress", goBack);
      };
```
After the navigation ends and the loop is restored, the init `i` is 3, then `i--`, `i` is 2, then `_backPressSubscriptions[2]` is `undefined` now and executes as a function, so the app crashes.
```js
for (let i = _backPressSubscriptions.length - 1; i >= 0; i--) {
    if (_backPressSubscriptions[i]()) {
      return;
    }
  }
```
that's the issue I met.

## Changelog:

<!-- Help reviewers and the release process by writing your own changelog entry.

Pick one each for the category and type tags:

[ANDROID] [FIXED] - Message

For more details, see:
https://reactnative.dev/contributing/changelogs-in-pull-requests
-->
[ANDROID] [FIXED] - Fix BackHandle callback undefined cause crash issue

Pull Request resolved: #48388

Reviewed By: blakef

Differential Revision: D67648077

Pulled By: rshest

fbshipit-source-id: 5ca685b0c0c474ef11772fd803743968ec2d912e
  • Loading branch information
BleemIs42 authored and facebook-github-bot committed Dec 27, 2024
1 parent 8dfed7d commit 44705fe
Showing 1 changed file with 1 addition and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const _backPressSubscriptions = [];

RCTDeviceEventEmitter.addListener(DEVICE_BACK_EVENT, function () {
for (let i = _backPressSubscriptions.length - 1; i >= 0; i--) {
if (_backPressSubscriptions[i]()) {
if (_backPressSubscriptions[i] && _backPressSubscriptions[i]()) {
return;
}
}
Expand Down

0 comments on commit 44705fe

Please sign in to comment.