-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Description
What happened?
Hi there, I have not clear behaviour when I disabled animation on showModal.
I want to call function when my screen appears. In IOS Stack "Appears" means when I go to this screen, and back to this screen my callback fn must be called. For that I wrote little hook:
export function useNavigationComponentDidAppear(handler: (ev: ComponentDidAppearEvent) => void, cId?: string) {
const ctx = React.useContext(NavigationContext);
const componentId = cId || ctx?.componentId;
useLayoutEffect(() => {
console.log('[HOOK LAYOUT EFFECT]');
const subscription = Navigation.events().registerComponentDidAppearListener((ev) => {
if (componentId === ev.componentId) handler(ev);
});
return () => subscription.remove();
}, [handler, cId]);
}Use it in my experiment screen:
export const SettingsView = ({ componentId }) => {
useNavigationComponentDidAppear(
React.useCallback(() => {
console.log('DID APPEAR SETTINGS VIEW');
}, []),
componentId,
);
return <View><Text>Settings screen</Text></View>
}Call showModal:
Navigation.showModal({
component: {
name: 'SETTINGS_VIEW',
}
});So when animations is on, everything is fine. I have logs:
LOG HOOK LAYOUT EFFECT
LOG RNN.appearedComponent name=SETTINGS_VIEW id=SETTINGS_VIEW
LOG DID APPEAR SETTINGS VIEW
But when I disable animations on modals
Navigation.setDefaultOptions({
animations: {
showModal: {
enter: {
enabled: false,
},
},
}})I called event before layout effect
LOG RNN.appearedComponent name=SETTINGS_VIEW id=SETTINGS_VIEW
LOG HOOK LAYOUT EFFECT
I got it that get RNN.appearedComponent event before I subscribed on it, so my callback wasn't called. I started investigate why that happens.
-
when we call
Navigation.showModal, we call RNNCommandHandler showModal on native -
RNNControllerFactory create new instance RNNComponentUiViewController
-
set reactViewReadyCallback - inside it we just natively open our modal.
-
run render method on RNNComponentUIController, inside it we do two thing
-
essentially
readyForPresentationcalled ourreactViewReadyCallbackthat start to show modal -
when modal open ends, RNNComponentUIController viewDidAppear will be triggered, and method RNNReactView componendDidAppear will send message to JS.
I guess in that point we have race condition:
- when animations is enabled we have extra time for render content of screen. So
RNNComponentUIController.viewDidAppear -> RNNReactView.componendDidAppear -> sendEventToJSwill be called after js render our screen component. - when animations is disabled we don't have extra time, and we called
RNNComponentUIController viewDidAppear-> RNNReactView componendDidAppear -> sendEventToJSbefore js render screen component;
We have RCTContentDidAppearNotification tells us that all subview of RCTRootContentView was show on screen. I know that we have flag waitForRender, but it waits for that event and only after that start open modal, so we can have little delay between tap and show modal. Instead we should send RNN.componentDidAppear event to JS when we get RCTContentDidAppearNotification
I did smth like this:
@implementation RNNReactView {
BOOL _isAppeared;
BOOL _isContentAppeared;
}
....
- (void)contentDidAppear:(NSNotification *)notification {
RNNReactView *appearedView = notification.object;
if ([appearedView.appProperties[@"componentId"] isEqual:self.componentId]) {
[self reactViewReady];
_isContentAppeared = true;
// send event RNN.ComponentDidAppear to js
[self componentDidAppear];
}
}
- (void)componentDidAppear {
// don't call until I get event RCTContentDidAppearNotification
if (!_isContentAppeared) return;
if (!_isAppeared) {
[_eventEmitter sendComponentDidAppear:self.componentId
componentName:self.moduleName
componentType:self.componentType];
}
_isAppeared = YES;
}
After that I get that log
LOG HOOK LAYOUT EFFECT
LOG RNN.appearedComponent name=SETTINGS_VIEW id=SETTINGS_VIEW
LOG DID APPEAR SETTINGS VIEW
I want to understand is this right behavior by default ?
Now I use waitForRender: true with disabled showModal animations, and it works as temporary solution
I can create repo with example.
Sorry for many letters =)
What was the expected behaviour?
When animations disabled I want get event RNN.componentDidAppear in my component
Was it tested on latest react-native-navigation?
- I have tested this issue on the latest react-native-navigation release and it still reproduces.
Help us reproduce this issue!
No response
In what environment did this happen?
React Native Navigation version:
React Native version:
Has Fabric (React Native's new rendering system) enabled: (yes/no)
Node version:
Device model:
iOS version: