Latest version, everything.
Currently, my drawer and photos scene is getting mounted twice
It should only mount once
Here is my code
render() {
return (
<View style={styles.container}>
<StatusBar/>
<Provider store={store}>
<ConnectedRouter navigationBarStyle={{backgroundColor:'#25abf9'}} titleStyle={{color:'white'}} headerTintColor="#FFF">
<Overlay>
<Stack key="root" hideNavBar hideTabBar>
<Stack key="public" titleStyle={{ alignSelf: 'center' }}>
<Scene key="login" component={Login} initial={true} title={'Login'} />
<Scene key="resetPassword" component={ResetPassword} title={'Reset Password'} />
</Stack>
<Drawer key="drawer" contentComponent={CustomDrawer} drawerImage={require('./images/ic_menu_white_24dp_2x.png')}>
<Stack key="main">
<Lightbox key="lightbox">
<Scene key='photos' component={Photos} title={'Home'} initial={false} navBar={CustomNavBar} />
<Scene key="disableOverlay" component={DisableOverlay} />
</Lightbox>
<Scene key='singlePhoto' component={SinglePhoto} title={'Photo'} photoDate={null} initial={false} navBar={CustomNavBarPhotos} />
<Scene key='photoDraw' component={PhotoDraw} title='Photo Edit' photoDate={null} initial={false} navBar={CustomNavBarUpload} />
<Scene key='photoUpload' component={PhotoUpload} title='Upload Photo' photoDate={null} initial={false} navBar={CustomNavBarUpload} />
<Scene key='sync' component={Sync} title='Syncing Data' initial={false} hideTabBar hideNavBar />
</Stack>
</Drawer>
</Stack>
</Overlay>
</ConnectedRouter>
</Provider>
<MessageBar/>
</View>
);
}
If I remove
Got same issue. But the first component is mounted 3 times.
Been debugging seems to be a caching issue of some kind, when the app goes to the background and then to the front again it mounts everything twice but not when you first load the app from a clean install
Switched to ^3.39.1 and everything works fine.
@nicovak not a real option, a lot of issues were fixed from that version
@AlmogRnD Yes I know but I also had an issue like clicking in TextInput was remounting the component... I didn't have these issues with 3.39
Yes I can't I'm using some of the new methods, this is a major issue
I fixed my TextInput by using react-navigation Drawer instead of react-native-drawer.
Still getting the first component mounted twice. Other components are mounted once.
How did you change it, can you send a code example?
Sure, I didnt change that much:
import React, { Component } from "react";
import {
Actions,
Scene,
Router,
Stack,
Drawer
} from "react-native-router-flux";
import { View, TouchableHighlight, StatusBar, StyleSheet } from "react-native";
import Icon from "react-native-vector-icons/Ionicons";
import SideMenu from "./components/common/SideMenu";
import Root from "./components/Root";
import Login from "./components/Login";
import Notifications from "./components/Notifications";
import Contact from "./components/Contact";
import Mentions from "./components/Mentions";
import { navbarHeight, statusBarheight } from "./components/common/Config";
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
openDrawer: false
};
}
handleDrawer() {
this.state.openDrawer ? Actions.drawerClose() : Actions.drawerOpen();
}
closeDrawer() {
Actions.drawerClose();
}
render() {
StatusBar.setBarStyle("light-content", true);
return (
<Router
hideNavBar={false}
titleStyle={styles.title}
navigationBarStyle={styles.navBar}
renderLeftButton={this._renderLeftButton()}
renderRightButton={this._renderRightButton()}
>
<Drawer hideNavBar key="drawer" contentComponent={SideMenu}>
<Stack key="root">
<Scene
key="home"
hideNavBar
component={Root}
renderLeftButton={null}
renderRightButton={null}
/>
<Scene
key="login"
hideNavBar
component={Login}
renderLeftButton={null}
renderRightButton={null}
/>
<Scene
key="notifications"
component={Notifications}
title="Notifications"
/>
<Scene key="contact" component={Contact} title="Contact" />
<Scene
key="mentions"
component={Mentions}
title="Mentions légales"
/>
</Stack>
</Drawer>
</Router>
);
}
_renderLeftButton() {
return (
<TouchableHighlight
underlayColor={"#f7f7f7"}
style={styles.buttons}
onPress={() => this.handleDrawer()}
>
<View style={styles.buttonNav}>
{this.renderOpenOrCloseIcon()}
</View>
</TouchableHighlight>
);
}
_renderRightButton() {
return (
<TouchableHighlight
underlayColor={"#f7f7f7"}
style={styles.buttons}
onPress={() => {
Actions.pop({ refresh: true });
}}
>
<View style={styles.buttonNav}>
<Icon name="ios-arrow-back" size={28} color="#4d215e" />
</View>
</TouchableHighlight>
);
}
renderOpenOrCloseIcon() {
if (this.state.openDrawer) {
return <Icon name="ios-close" size={30} color="#4d215e" />;
} else {
return <Icon name="ios-menu" size={30} color="#4d215e" />;
}
}
}
const styles = StyleSheet.create({
navBar: {
justifyContent: "flex-start",
height: navbarHeight + statusBarheight
},
title: {
alignSelf: "center"
},
buttons: {
padding: 13
},
buttonNav: {
alignItems: "center",
justifyContent: "center",
alignSelf: "center"
}
});
I have a similar issue. I have outside of the Router component other components (alerts). If their states are updated, the Router component will be re-rendered, but it Router re-mount the current scene, which followers to the lost of the current state. Seems to be very similar to the onPress event of our TextInput, @nicovak.
According to my experience, which happens when React components have no keys and React can not find the component on re-rendering. It creates a new component instance for the current rendering. I investigated the code to find the rendering of the component in the router scenes.
src/navigationStore.js:314 (processScene()) is the method where all scenes "get hooked". In src/navigationStore.js:368 starts the iteration over all scenes and in src/navigationStore.js:391 the scenes get wrapped by createWrapper() (see src/navigationStore.js:209). In my point of view this is necessary to pass the props to the scene component.
In createWrapper() are two options for stateless components and not stateless component. In both cased (see definitions below) I run into the stateless component path. I tried to add a extra key there for React at the definition of this instance, but without any change. What you should notice there is, that in both cases the returned component instance is wrapped by the props wrapper function, which is defined in src/navigationStore.js:303 as:
wrapBy = props => props
Thats the point where I stopped understanding the behavior if the code. Actually this helps to solve the issue.
Scene definition with stateless component
<Scene
key="LandingEmail"
component={(props) => (
<SceneLandingEmail
key="SceneLandingEmail"
setAlertMessages={this.props.setAlertMessages}
userSignedIn={this.props.userSignedIn}
/>
)}
hideNavBar={true}
/>
Scene definition without stateless component
<Scene
key="LandingEmail"
component={SceneLandingEmail}
hideNavBar={true}
/>
@aksonov have you had a chance to look at this, pretty much a major issue?
@jankarres if I understand you correctly what you're saying is that the issue is cased when the router loads components that then load internal components?
For example, I have a drawer
<Drawer key="drawer" contentComponent={CustomDrawer} drawerImage={require('./images/ic_menu_white_24dp_2x.png')}>
That loads CustomDrawer which loads another component NavMenue
<View style={styles.container}>
<NavMenu/>
<Button style={{paddingBottom:15}} backgroundColor="red" title='Logout' onPress={() => {this._validateLogout()}}/>
</View>
Is that correct?
I tried what you suggested but then I get
TypeError: _reactNativeRouterFlux.Actions.photos is not a function
When I call Actions.photos
@AlmogRnD Thanks for your reply. No, I think you have not git the point. I created a very simplified example project.
npm install && npm start
In the app, you can type a text into the TextInput, which is saved to the state of the SceneExample. If you click on the button below, the arrow function will call the setter of App and set new alert messages, which are rendered in Alert.
Should: React re-renders the Alert component with new props
Actual: React re-renders the Alert component with new props and remount the SceneExample component
This behavior sound similar to yours issue, but more similar to @nicovak's app behaviour.
Project: react-native-router-flux_issue_2382_example_2017_09_14.zip
@jankarres I see, my understanding each time update the state react does render or run will update in the component lifecycle that is the expected behavior.
My issue is different and should not happen
Please reproduce it with Example project
14 сент. 2017 г., в 10:57, Almog Koren notifications@github.com написал(а):
@aksonov have you had a chance to look at this, pretty much a major issue?
@jankarres if I understand you correctly what you're saying is that the issue is cased when the router loads components that then load internal components?
For example, I have a drawer
That loads CustomDrawer which loads another component NavMenue
Is that correct?I tried what you suggested but then I get
TypeError: _reactNativeRouterFlux.Actions.photos is not a functionWhen I call Actions.photos
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.
@aksonov that doesn't do anything my project is different, the routing is different, I'm using redux, ect.... So maybe the example project works but that does not mean there are no issues with the lib.
@AlmogRnD You are right that "each time update the state react does render or run will update in the component lifecycle", but it should not unmount and remount the component, if a key is specified. If I use the same code without the router, this behaviour will not appear.
Actually it is a different issue. For this reason I opened a own issue.
@AlmogRnD you must reproduce issue with some github repo. Otherwise I cannot help, sorry. Also you need to make sure that it is NOT react-navigation issue.
@aksonov I checked react-navigation while there is a similar issue it's different it happens on the back button, not on loading like my issue, second if I downgrade to an older version of react-navigation-flux this does not happen so it's with the new updates.
I can't create a demo up like what I have to create the issue as I'm code is already big but I might be able to give you access to my project for you to test
@aksonov I think it has to do with init happing twice, check out the screenshot

@aksonov I did some more debugging, seems the issue is caused by the drawer or at least it's related.
I have <Drawer key="drawer" contentComponent={CustomDrawer} drawerImage={require('./images/ic_menu_white_24dp_2x.png')}>
If I remove the key everything is fine
<Drawer contentComponent={CustomDrawer} drawerImage={require('./images/ic_menu_white_24dp_2x.png')}>
But the issue with that is that I get a new error
Possible Unhandled Promise Rejection (id: 0):
Invariant Violation: There is no route defined for key key1.
Must be one of: 'public','key2'
Invariant Violation: There is no route defined for key key1.
Must be one of: 'public','key2'
@aksonov by the way this only happens on reload, i.e. when app the loads for the first time no problem. But if the app goes to the background or I reload vis sim this issue happens
@aksonov I believe this is the same issue https://github.com/wix/react-native-navigation/issues/800
For now my workaround is not to run the set state method while it's loading, this solves the issue with the errors and I just have the overhead issue of running redux calls twice but not a big deal for now
I've found a pretty simple workaround. The router will be triggered if the next scene is not the current.
for example:
itemPress() {
if (Actions.currentScene == "ItemScene") return;
Actions.ItemScene();
}
I had the same issue when I did it like this:
<Scene
...
drawerIcon={<DrawerButton/>}>
renderRightButton={<RightButton/>}
...
/>
I fixed it by doing it like this:
<Scene
...
drawerIcon={() => <DrawerButton/>}>
renderRightButton={() => <RightButton/>}
...
/>
(I'm new to RN so this might be trivial to do it like that, maybe it helps anyone fixing the problems as well)
I am using BackHandler.addEventListener to manually overwrite Back Button Press. but If I use, Actions.pop() in BackHandler.addEventListener callback function. and use Actions.push('Screen'). Every Screen is MOUNTING - UNMOUNTING and then MOUNTING again.
BackHandler.addEventListener('hardwareBackPress', () => {
Actions.pop();
Actions.push(store.getState().goBackScreen);
return true;
}
@jalilahmed You're using the navigation really bad here, what you should do is something like this :
onBackPress() {
if (Actions.state.index === 0) {
return false
}
Actions.pop()
return true
}
And then in the Router :
<Router backAndroidHandler={this.onBackPress}>
Then, whenever you want to override this function in a component to do a specific thing, just do as following :
componentDid(Will)Mount() {
this.myOwnBackPressHandler = BackHandler.addEventListener('myOwnBackPressHandler', () => {
if (Actions.currentScene === 'aSpecificScene' && someConditionIsTrue) {
Actions.replace('anotherSpecificScene', { someProp: somePropValue }) // THIS IS AN EXAMPLE
return true
}
return false
})
}
componentWillUnmount() {
this.myOwnBackPressHandler.remove()
}
Closed due inactivity. Looks like the issue not in RNRF (because it doesn't mount/render scenes at all, but calls react-navigation): react-navigation/react-navigation#476
@aksonov
I had the same issue (all components were mounting twice and even more times). I did
1) rm -rf $TMPDIR/react-* && rm -rf node_modules/ && npm cache clean && npm install && npm start -- --reset-cache
2) cd android && ./gradlew clean
After this I could only reproduced double mounting of one scene with "inital" prop.
I'am shore this bug is related to building of react-native itself
I'm running into this.
Most helpful comment
Sure, I didnt change that much: