Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix!: always set Zindex to undefined for InnerScreen #2351

Merged
merged 2 commits into from
Sep 26, 2024

Conversation

adrianryt
Copy link
Contributor

@adrianryt adrianryt commented Sep 25, 2024

Description

Together with @kkafar we noticed that when switching back between BottomTabsView (A -> B -> A) , React is calling removeScreenAt and addScreen for tab we are leaving - in the same transaction! Because of that and asynchronous nature of react-native-screens, error described in #2345 exist. We also noticed that this weir behaviour is related to setting ZIndex in InnerScreen.

Fixes #2345

Test 2232 was failing due to change in headerBackTitleVisible property.

Caution

@kkafar:
Note that this change might be potentially breaking since we're effectively removing possibility of managing Screen components through "z indices", breaking public API.

@kkafar:
The error mechanism is as follows:

  1. zIndex being set causes RN diffing mechanism to include two mutations on the same view in the same transaction - effectively detaching and attaching it,
  2. Thus when we navigate from tab B to A, react first detaches B from screen container and in the same transaction it attaches it again - however at the moment of reattach react expects B to be detached. This is not case due to the fact, that we don't execute updates synchronously, but rather we just schedule them in another block on UI thread;
  3. React asserts the invariant from point 2., and when we violate it, its internal state gets corrupted later leading to crash.

We detected that getting rid of setting zIndex on screens prevents the two consecutive operations on the same screen to appear, thus effectively solving the problem.

Note, however, that we still won't support such cases with multiple mount/unmount mutations related to the same component in single transaction.

Changes

  • For every InnerScreen created we set/override ZIndex style to undefined.
  • Use headerBackButtonDisplayMode instead of headerBackTitleVisible.

Test code and steps to reproduce

Checklist

@adrianryt adrianryt changed the title Always set Zindex to undefined for InnerScreen Fix: Always set Zindex to undefined for InnerScreen Sep 25, 2024
@adrianryt adrianryt changed the title Fix: Always set Zindex to undefined for InnerScreen fix: Always set Zindex to undefined for InnerScreen Sep 25, 2024
@adrianryt adrianryt force-pushed the always-set-zindex-to-undefined-for-InnerScreen branch from 65b1b74 to f4d0502 Compare September 25, 2024 14:32
Co-authored-by: Kacper Kafara <kacperkafara@gmail.com>
@adrianryt adrianryt force-pushed the always-set-zindex-to-undefined-for-InnerScreen branch from f4d0502 to dd33cdb Compare September 25, 2024 14:41
@kkafar kkafar changed the title fix: Always set Zindex to undefined for InnerScreen fix!: always set Zindex to undefined for InnerScreen Sep 25, 2024
@adrianryt adrianryt marked this pull request as ready for review September 25, 2024 15:24
@@ -125,6 +126,7 @@ export const InnerScreen = React.forwardRef<View, ScreenProps>(
<DelayedFreeze freeze={freezeOnBlur && activityState === 0}>
<AnimatedScreen
{...props}
style={[style, { zIndex: undefined }]}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd add a comment that we are handling the order of screens on the native side and changing it here causes issues, with the link to the issue.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

Copy link
Member

@kkafar kkafar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, beside the comment and testing on react-navigation v6 I think we're good. Let me know once the comment is added (mark me for another review).

I've enhanced the PR description, so we can better reconstruct the error mechanism in case its needed in few months.

@@ -125,6 +126,7 @@ export const InnerScreen = React.forwardRef<View, ScreenProps>(
<DelayedFreeze freeze={freezeOnBlur && activityState === 0}>
<AnimatedScreen
{...props}
style={[style, { zIndex: undefined }]}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

@kkafar kkafar added the NewArch Issues related only to new architecture label Sep 26, 2024
Copy link
Member

@kkafar kkafar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I think we're good to go. Thank you very much 🎉

@kkafar kkafar merged commit 53695c3 into main Sep 26, 2024
3 checks passed
@kkafar kkafar deleted the always-set-zindex-to-undefined-for-InnerScreen branch September 26, 2024 14:30
ja1ns pushed a commit to WiseOwlTech/react-native-screens that referenced this pull request Oct 9, 2024
…n#2351)

## Description
Together with @kkafar we noticed that when switching back between
BottomTabsView (A -> B -> A) , React is calling removeScreenAt and
addScreen for tab we are leaving - in the same transaction! Because of
that and asynchronous nature of react-native-screens, error described in
software-mansion#2345 exist. We also noticed that this weir behaviour is related to
setting ZIndex in InnerScreen.

Fixes software-mansion#2345

Test 2232 was failing due to change in headerBackTitleVisible property.

> [!Caution]
@kkafar:
Note that this change might be potentially breaking since we're
effectively removing possibility of managing `Screen` components through
"z indices", breaking public API.

@kkafar:
The error mechanism is as follows:

1. `zIndex` being set causes RN diffing mechanism to include two
mutations on the same view in the same transaction - effectively
detaching and attaching it,
2. Thus when we navigate from tab B to A, react first detaches B from
screen container and in the same transaction it attaches it again -
however at the moment of reattach react expects B to be detached. This
is not case due to the fact, that we don't execute updates
synchronously, but rather we just schedule them in another block on UI
thread;
3. React asserts the invariant from point 2., and when we violate it,
its internal state gets corrupted later leading to crash.

We detected that getting rid of setting `zIndex` on screens prevents the
two consecutive operations on the same screen to appear, thus
effectively solving the problem.

Note, however, that we still won't support such cases with multiple
mount/unmount mutations related to the same component in single
transaction.

## Changes


- For every InnerScreen created we set/override ZIndex style to
undefined.
- Use headerBackButtonDisplayMode instead of headerBackTitleVisible.


## Test code and steps to reproduce


## Checklist

- [ ] Included code example that can be used to test this change
- [ ] Updated TS types
- [ ] Updated documentation: <!-- For adding new props to native-stack
-->
- [ ]
https://github.com/software-mansion/react-native-screens/blob/main/guides/GUIDE_FOR_LIBRARY_AUTHORS.md
- [ ]
https://github.com/software-mansion/react-native-screens/blob/main/native-stack/README.md
- [ ]
https://github.com/software-mansion/react-native-screens/blob/main/src/types.tsx
- [ ]
https://github.com/software-mansion/react-native-screens/blob/main/src/native-stack/types.tsx
- [ ] Ensured that CI passes

---------

Co-authored-by: Kacper Kafara <kacperkafara@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
NewArch Issues related only to new architecture
Projects
None yet
Development

Successfully merging this pull request may close these issues.

No view found for id 0x20 (unknown) for fragment ScreenFragment Android in React-Native 0.75
3 participants