GeekyAnts / react-native-hamburger

Hamburger menu for react-native!
MIT License
134 stars 25 forks source link

UI does not update on state change #1

Open cbetta opened 7 years ago

cbetta commented 7 years ago

Currently it seems the active param doesn't listen to the provided state, as a result it doesn't seem to update when the state changes.

dereksweet commented 7 years ago

I can verify this is indeed an issue. So long as you modify the state by clicking the hamburger then it animates properly. If you modify the state outside of the hamburger component the hamburger does not animate.

I got a workaround to work by creating a ref to the hamburger and then calling the ._animate() function manually whenever I update the state:

// clickNavLink is called outside of Hamburger from a nav bar that pops up. 
const clickNavLink = (pane) => {
  routingActions.setVisiblePane(pane);
  statusBarActions.toggleHamburgerActive();
  this.hamburger._animate();
};

<Hamburger ref={hamburger => { this.hamburger = hamburger }}
           active={state.hamburger_active}
           type="spinCross"
           color="black"
           onPress={() => statusBarActions.toggleHamburgerActive()} />
cbetta commented 7 years ago

Tnx for the tip @dereksweet, that might work for me.

tetreault commented 7 years ago

@Nyl000 @sankhadeeproy007 the latest pull request which added this in Hamburger.js

    componentWillReceiveProps(nextProps) {
        if (nextProps.active !== this.state.active) {
            this._animate();
        }
    }

Doesn't seem to resolve my problem. I have a Hamburger button from this module, I click it, it animates once, and never animates again.

I can console log out the state of the icon, when clicking it indicates the correct expected state, but never animates back. Click once, animates from the three lines to the X, click, state prints out right, never animates.

tetreault commented 7 years ago

Here's the full, small component file in which I have this hamburger button, located in a folder in my project src/components/HamburgerButton.js.

'use strict';

import Expo from 'expo';
import React from 'react';
import {
  StyleSheet
} from 'react-native';
import Hamburger from 'react-native-hamburger';

export default class MenuButton extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      active: false
    };
  }

  render() {
    return (
      <Hamburger
        active={this.props.active}
        type='spinCross'
        onPress={() => this.setState({ active: !this.state.active })} />
    );
  }
}
Nyl000 commented 7 years ago

@tetreault Shouldnt you use active={this.state.active} instead of active={this.props.active} in this case ? You change state on press.

tetreault commented 7 years ago

Good catch @Nyl000 - that was my bad. I've since refactored the HamburgerButton.js a bit because I needed to emit state change in conjunction with react-native-side-menu. My following code works - i can see state updating in the console.log of Expo correctly. However the button still only changes its state once.

'use strict';

import Expo from 'expo';
import React from 'react';
import {
  StyleSheet
} from 'react-native';
import Hamburger from 'react-native-hamburger';
import Actions from '../actions/Actions';
import Store from '../store/Store';

export default class MenuButton extends React.Component {
  constructor(props) {
    super(props);
    // get initial state from Store
    this.state = {
      active: Store.getStore().menuState
    };
    this._onPress = this._onPress.bind(this);
    this._changeState = this._changeState.bind(this);
    console.log('Hamburger this', `${JSON.stringify(this)}`);
  }

  // state changed, get updated state from store
  _changeState() {
    this.state = {
      active: Store.getStore().menuState
    };
    console.log('Hamburger State Updated', `${JSON.stringify(this.state.active)}`);
  }

  // menu icon was pressed, fire action to update state
  _onPress() {
    console.log('Hamburger _onPress called');
    Actions.toggleMenu(!this.state.active);
  }

  // mount event listener that will talk to store and trigger this._changeState
  componentDidMount() {
    console.log('Hamburger componentDidMount called');
    Store.addChangeListener(this._changeState);
  }

  render() {
    return (
      <Hamburger
        active={this.state.active}
        type='spinCross'
        onPress={this._onPress} />
    );
  }
}
screenshot 2017-05-17 14 01 36
Nyl000 commented 7 years ago

Your code seems right indeed.

Here is a short version of my code, it's working well, hope it can help:

(onClick event on MenuFade is just a callback when users tap menu elements)

constructor(props) {
    super(props);
    this.state = {menuVisible: false};
}

_toggleMenu = () => {
    this.setState({
        menuVisible: !this.state.menuVisible,
    });

};

render() {
    return (
        <View>
            <Hamburger active={this.state.menuVisible}
                       type="spinCross"
                       color="white"
                       style={{zIndex: 100,position: 'relative'}}
                       onPress={this._toggleMenu}/>
            <MenuFade isVisible={this.state.menuVisible} navigator={this.navigator} onClick={this._toggleMenu}/>
        </View>
    );
}
nickineering commented 5 years ago

Best I can tell this is still happening, even after the PR. I'm updating active and the animation is not occuring.

nickineering commented 5 years ago

This issue would be resolved by #5. I tested that PR myself and everything works fine now.