timomeh / react-native-material-bottom-navigation

πŸ’…πŸ”§πŸ‘Œ a beautiful, customizable and easy-to-use material design bottom navigation for react-native
MIT License
709 stars 127 forks source link

onTabChange is called twice #35

Closed Maxeh closed 7 years ago

Maxeh commented 7 years ago

The onTabChange function is in 80% of the cases (but not always) executed twice. The first time with the actual new tabIndex, the second time with the tabIndex 0. This only occurs when I use setState in the function. See my example code:

      {this.state.page === "Screen1" && <HomeScreen navigation={this.props.navigation}/>}
      {this.state.page === "Screen2" && <View><Text>hihihihi</Text></View>}
      {this.state.page === "Screen3" && <View><Text>hallo welt</Text></View>}
      {this.state.page === "Screen4" && <View><Text>hallo welt123</Text></View>}
      {this.state.page === "Screen5" && <View><Text>hihihihi</Text></View>}

      <BottomNavigation
        labelColor="black"
        rippleColor={GLOBAL.COLOR.ORANGE}
        style={{ height: 56, elevation: 8, position: 'absolute', left: 0, bottom: 0, right: 0 }}
        onTabChange={(newTabIndex) => {
          alert(newTabIndex);
          switch(newTabIndex) {
            case 0: this.setState({page: 'Screen1'}); break;
            case 1: this.setState({page: 'Screen2'}); break;
            case 2: this.setState({page: 'Screen3'}); break;
            case 3: this.setState({page: 'Screen4'}); break;
            case 4: this.setState({page: 'Screen5'}); break;
          }
          console.log(this.state);
        }}
        shifting={false}
      >

So for example, when I click on TabIcon 3, it becomes active for one second and then the first tabIcon becomes active. Does someone know how I can resolve this issue?

timomeh commented 7 years ago

Try to also save the activeTab (newTabIndex) in your state and use <BottomNavigation activeTab={this.state.activeTab} ... />.

I provided an example for this, see: https://github.com/timomeh/react-native-material-bottom-navigation/blob/e5560123c345901b4a4d397837ff4846075a2ffe/example/StatefulBottomNavigaion.js

I didn't encounter an issue where onTabChange gets executed twice using this approach, so give it a try. πŸ™‚ I hope it'll work.

Maxeh commented 7 years ago

@timomeh thanks for the quick reply, seems to work now. I deleted the following function and got it also to work:

componentWillReceiveProps(nextProps: BottomNavigationProps) {

const { activeTab: newTabIndex } = nextProps
const { activeTab: oldTabIndex } = this.state
const { nextActiveTab } = this
const tabAmount = this.props.children.length

/* !! The following code leads to a bug where setActiveTab() is called twice
// Change active tab when activeTab-prop changes
if (newTabIndex !== oldTabIndex && newTabIndex !== nextActiveTab) {
  // Test index out of bounce
  if (newTabIndex < 0 && newTabIndex >= tabAmount) {
    if (__DEV__) console.error(`${newTabIndex} is not a valid tabIndex`)
  } else {
    this.refs[`tab_${newTabIndex}`].setTabActive()
  }
}*/
}

Not sure if you really need this function, but seems to work without it. But now I'm just using your proposed solution where I store activeTab in the state.

timomeh commented 7 years ago

@Maxeh This code snippet is necessary to prevent a rerender of the component when it doesn't need to rerender.
The background behind this is that pressing a tab causes it to become active "internally" and the ripple animation will run, but if the activeTab is also stored in the state and is "externally" connected with activeTab={this.state.activeTab}, the changed prop will cause the animation to run another time. In that case the ripple would be visible two times. The code inside componentWillReceiveProps prevents this.

In the planned rewrite of this component, I'll write a better solution for this.

For now I think this issue is closed. Please reopen if there are still issues regarding this.

54vanya commented 7 years ago

Hello, got double firing too, first tab works good, but on second id fires twice, and second firing gives 0 as active tab, @Maxeh solution works for me, but editing node module isn't good idea

Maxeh commented 7 years ago

@54vanya try to apply timomeh's solution, it works for me fine.

Try to also save the activeTab (newTabIndex) in your state and use -BottomNavigation activeTab={this.state.activeTab} ... />....