navigation: Error when trying to switch components in a scene[Android]
Note: Looks like i seem to have the most issues opened here and i am not terribly keen on that title but this one has me stumped. I re-read the docs and searched the issue list and SO but just couldn’t find a resolution for my latest issue. An Android-only issue again.
I am getting the following (red screen)error when i attempt to switch components in my main entry file:
Trying to remove a view index above child count 0
view tag:33
detail: View tag: 33
children(0):[],
indicesToRemove(1):[0,],
tagsToDelete(1):[29,]
...
...
My App.js
does the initial registering etc and i navigate to my Welcome
scene as the default entry for the app. Here i expect to start with some initial background API calls etc while presenting an intermediary Loader
component to the user. If all goes well i then present the welcome screen to the user. I may use redux
or context
but for simplicity i now simulate it via a simple setTimer
and in-component state
. Everything works fine on IoS(in fact i can even auto redirect/navigate to another scene in IoS) but on Android i get the error i listed above. This error only happens when the timer completes and the switch is attempted i.e I get the loader component displayed as expected for 5 seconds and then the error shows up.
My App.js
import React from 'react';
import {Alert, BackHandler} from 'react-native';
import { StateNavigator } from 'navigation';
import {NavigationHandler} from 'navigation-react';
import {NavigationStack} from 'navigation-react-native';
import {MenuProvider} from 'react-native-popup-menu';
import {Provider} from 'react-redux';
import store from './src/redux/store';
import Menu from './src/scenes/Menu/Menu';
import Welcome from './src/scenes/Welcome/Welcome';
const stateNavigator = new StateNavigator([
{
key: 'welcome',
trackCrumbTrail: true
}, {
key: 'menu',
trackCrumbTrail: true
}
])
const {welcome, menu} = stateNavigator.states;
welcome.renderScene = () => <Welcome/>;
menu.renderScene = () => <Menu/>;
stateNavigator.navigate('welcome');
class App extends React.Component {
componentDidMount() {
BackHandler.addEventListener("hardwareBackPress", this._handleHardwareBackPress);
}
componentWillUnmount() {
BackHandler.removeEventListener("hardwareBackPress", this._handleHardwareBackPress)
}
_handleHardwareBackPress = (args) => {
if (!stateNavigator.canNavigateBack(1)) {
Alert.alert("Show a prompt with OK/CANCEL")
return true
}
}
render() {
return (
<MenuProvider>
<Provider store={store}>
<NavigationHandler stateNavigator={stateNavigator}>
<NavigationStack/>
</NavigationHandler>
</Provider>
</MenuProvider>
);
}
}
export default App;
My Welcome.js
import { NavigationContext } from 'navigation-react';
import React, { Component } from 'react';
import { StyleSheet } from 'react-native';
import AppLoaderCmp from '../../components/AppLoader/AppLoader';
import WelcomeCmp from '../../components/Welcome/Welcome';
class Welcome extends Component {
state={
loaded: false
}
componentDidMount(){
setTimeout(()=>this.setState({loaded:true}),5000)
}
render() {
return (
<NavigationContext.Consumer>
{({stateNavigator}) => {
return this.state.loaded
?<WelcomeCmp stateNavigator={stateNavigator} />
: <AppLoaderCmp stateNavigator={stateNavigator} />
}
}
</NavigationContext.Consumer>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#E91E63'
},
});
export default Welcome;
My Welcome component
import React from 'react';
import {Button, SafeAreaView, StyleSheet, Text} from 'react-native';
//import {gotoScreen, routesKeys} from '../../routes';
const WelcomeCmp = (props) => <SafeAreaView style={styles.container}>
<Text>
Welcome
</Text>
<Button
title="To Menu Screen"
// onPress={() => gotoScreen(routesKeys.MENU, stateNavigator)}
onPress={() => console.log('Pressed the Menu button')}
/>
<Button
title="To Admin Screen"
//onPress={() => gotoScreen(routesKeys.ADMIN, stateNavigator)}
onPress={() => console.log('Pressed the Admin button')}
/>
<Button title="Open SideDrawer"
//onPress={this._openDrawer}
onPress={() => console.log('Pressed the SideDrawer button')}
/>
</SafeAreaView>
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#E91E63'
}
});
export default WelcomeCmp;
My AppLoader component:
import React from 'react';
import {SafeAreaView, StyleSheet, Text} from 'react-native';
const AppLoaderCmp = (props) => <SafeAreaView style={styles.container}>
<Text>
App Loader
</Text>
</SafeAreaView>
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#E91E63'
}
});
export default AppLoaderCmp;
I am using the latest version Navigation React Native
since i did an unlink/remove and re-added the libraries:
...
"navigation": "^5.2.0",
"navigation-react": "^4.1.1",
"navigation-react-native": "^5.4.0",
...
I initially had a slightly more ‘twisted’ setup. I only did a renderScene()
for my entry scene, and wanted to dynamically render the scene on demand where required. It does work though i am not sure if it is optimal. Ive reverted back to a simple example to check if the issue can be reproduced. It can. I also tried via checks in componentDidUpdate
but get the same error. All my attempts of course work perfectly fine in IoS.
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Comments: 15 (15 by maintainers)
I definitely will. Currently i am re-architecting my (rather verbose/code-heavy)app to use
React Hooks
- first attempt at it - andTypescript
(first official attempt). This is after attempting to change the structure tore-ducks
, an enhancedduck
pattern. Using hooks may sort of nullify the need for adhering to a strict duck pattern, and i am still figuring out an optimal approach.There are a few expected and unexpected stumbling blocks and am currently prioritising fixing these issues. Including the current urgent need to to integrate
Crashlytics
and/orFlipper
since the app crashes inexplicably at odd times and so far haven’t found the reason why. My current guess is that its inefficient use of one or moreuseEffect
hooks. And the all important reason whyauth
requests to Firebase isn’t just completing as it did just a few days ago.Will send PRs/ideas for consideration as soon as the big issues are done with. As of now i suspect it may be Android-only but with some more thought, maybe cross-platform.
[Incidentally, the inspiration to move to hooks and typescript came courtesy reading the Navigation Router source and examples]
You must move the
MenuProvider
inside your scene. Its name is confusing. It isn’t like aReduxProvider
because it renders UI elements.It is caused by the Navigation router. The Navigation router doesn’t like it when you change the first child of a Scene. I won’t reopen this though because I think it’s fair to assume the first child won’t change