问题
I am using react-native with react-navigation@1.5.11.
Environment:
OS: macOS High Sierra 10.13.1
Node: 8.9.2
Yarn: 1.5.1
npm: 5.8.0
Watchman: 4.9.0
Xcode: Xcode 9.1 Build version 9B55
Android Studio: 3.1 AI-173.4720617
Packages: (wanted => installed)
react: 16.3.1 => 16.3.1
react-native: 0.55.2 => 0.55.2
I am using StackNavigator and TabNavigator and my router setup like below:
const BillStack = StackNavigator({
Bill: { screen: Bill },
CompletedBill: { screen: CompletedBill }
},
{ headerMode: 'none' });
export default TabNavigator(
{
Bill: { screen: BillStack },
AddBill: { screen: AddBill },
Setting: { screen: Setting }
},
{
navigationOptions: ({ navigation }) => ({
tabBarIcon: ({ focused, tintColor }) => {
const { routeName } = navigation.state;
let iconName;
switch(routeName) {
case 'Bill':
iconName = `ios-albums${focused ? '' : '-outline'}`;
break;
case 'AddBill':
iconName = `ios-add-circle${focused ? '' : '-outline'}`;
break;
case 'Setting':
iconName = `ios-cube${focused ? '' : '-outline'}`;
break;
default:
iconName = `ios-albums${focused ? '' : '-outline'}`;
}
return <IconIonicons name={iconName} size={27} color={tintColor} />;
}
}),
tabBarOptions: {
activeTintColor: AppStyles.defaultTextBlueColor,
inactiveTintColor: '#ABB2B9',
showLabel: false,
style: {
backgroundColor: '#FFFFFF',
borderTopColor: AppStyles.navbarAndTabbarBorderColor
}
},
tabBarComponent: TabBarBottom,
tabBarPosition: 'bottom',
animationEnabled: true,
swipeEnabled: false
}
);
Bill component and CompletedBill component are on the same stack and user can navigate to CompletedBill component by tabbing on the upper right hand icon.
class Bill extends React.Component {
render () {
return (
<Container style={AppStyles.defaultScreenStyle}>
<Header style={AppStyles.defaultHeaderStyle}>
{this.renderNavBarLeftButton()}
<Body>
<Title style={AppStyles.headerTextStyle}>My Task</Title>
</Body>
<Right>
<Button transparent onPress={() => this.props.navigation.navigate('CompletedBill')}>
<IconIonicons name='ios-archive-outline' size={35} color="#263238"/>
</Button>
</Right>
</Header>
</Container>
);
}
}
My CompletedBill component code
class CompletedTask extends React.Component {
componentWillMount() {
console.log('CompletedTask componentWillMount');
}
componentDidMount() {
console.log('CompletedTask componentDidMount');
}
componentWillUnmount () {
console.log('CompletedTask componentWillUnmount');
}
componentWillReceiveProps() {
console.log('CompletedTask componentWillReceiveProps');
}
render () {
return (
<Container style={AppStyles.defaultScreenStyle}>
<Header style={AppStyles.defaultHeaderStyle}>
<Left>
<Button
transparent
onPress={() => this.props.navigation.dispatch({ type: 'Navigation/BACK' })}>
<IconIonicons name='ios-arrow-back' size={30}/>
</Button>
</Left>
<Body style={{flex: 3}}>
<Title style={AppStyles.headerTextStyle}>My Completed Bill</Title>
</Body>
<Right>
<Button transparent>
</Button>
</Right>
</Header>
</Container>
);
}
}
Everytime user tab on the upper right icon on Bill component screen, it will bring them to CompletedBill component and everytime the entire CompletedBill component re-render as all the componentWillMount, componentDidMount and etc get called.
Anyway to prevent from re-rendering? Or it's a common behavior?
回答1:
This is the intended behavior of StackNavigator.
In your StackNavigator, CompletedBill is declared after Bill (objects are meant to be unordered, but this library makes use of it),
When you navigate from Bill to CompletedBill, CompletedBill is pushed to the stack (with Bill underneath it so Bill doesn't get unmounted).
When you navigate from CompletedBill to Bill, CompletedBill is popped from the stack and gets unmounted.
Solution
If you don't want CompletedBill to be unmounted when switching between it and Bill, you should use a TabNavigator instead of StackNavigator. You can hide the tab bar by setting tabBarVisible: false in TabNavigator's navigationOptions.
来源:https://stackoverflow.com/questions/50086021/react-navigation-make-component-keep-re-rendering-when-navigate-to-other-screen