Вопрос:

lock/prevent close of menu reactjs

javascript reactjs menu state

47 просмотра

2 ответа

143 Репутация автора

I have a side menu that opens when an icon is clicked and closes when the either the page is clicked or an item on the menu is clicked. I am trying to implement a lock so when the lock icon is clicked, the menu will not close even if you click on a menu item or on the page.

I was able to setup the icon changing from a locked one to an unlocked one but I am having trouble with the functionality of stopping the close. Any help/suggestions would be awesome. Below are the 2 components that (the parent and the menu with the lock button) here is the code sandbox for a full look: https://codesandbox.io/s/pw6q46jp20

class SideBar extends Component {
  constructor(props) {
    super(props);
    this.state = {
      category: props.category,
      currentPage: {
        backgroundColor: '#383838',
        color: '#A9A9A9',
      },
      menuLocked: false,
      menuOpen: false,
      selectedIcon: null,
    };
  }
  handleIconClick = (category) => {
    this.setState({
      category,
      menuOpen: true,
      selectedIcon: category,
    });
  };
  handleMenuItemClick = (category) => {
    this.setState({
      menuOpen: false,
      selectedIcon: '',
      currentPage: category,
    });
  }
  handlePageClick = () => {
    this.setState({
      menuOpen: false,
    });
  }
  handleMenuLock = () => {
    this.setState({ menuLocked: !this.state.menuLocked });
  }
  render() {
    return (
      <div>
        <TopBar {...this.props} />
        <Container>
          <SideNav>
            <ListWrapper>
              <IconList
                currentPage={this.state.currentPage}
                openMenu={this.handleIconClick}
                selectedIcon={this.state.selectedIcon}
                visible={this.state.menuOpen}
              />
            </ListWrapper>
          </SideNav>
          <PageContentWrapper>
            <Sidebar.Pushable>
              <PushMenu
                category={this.state.category}
                closeOnItemClick={this.handleMenuItemClick}
                handleMenuLock={this.handleMenuLock}
                menuLocked={this.state.menuLocked}
                params={this.props.params}
                visible={this.state.menuOpen}
              />
              <Sidebar.Pusher
                onClick={this.handlePageClick}>
                <Segment basic>
                  {this.props.children || <Home />}
                </Segment>
              </Sidebar.Pusher>
            </Sidebar.Pushable>
          </PageContentWrapper>
        </Container>
      </div>
    );
  }
}

SideBar.propTypes = {
  children: PropTypes.any,
  params: PropTypes.any,
  category: PropTypes.any,
};

export default SideBar;

class PushMenu extends React.Component {
  render() {
    const category = sideNavData.lookupCategory(this.props.category);
    const menuLockButton = !this.props.menuLocked
      ? <Icon
        link={true}
        name='unlock'
        size='big'
      />
      : <Icon
        link={true}
        name='lock'
        size='big'
      />;
    return (
      <Sidebar
        className='Push-menu'
        animation='push'
        width='thin'
        visible={this.props.visible}
      >
        <Header>{this.props.category}</Header>
        <Linebreak />
        {
          Object.keys(category).map((subCategory, index) => {
            return (
              <div key={index}>
                <SubcategoryHeader>{subCategory}</SubcategoryHeader>
                <List>
                  {
                    Object.keys(category[subCategory]).map((item, index) => (
                      <li key={index}>
                        <ListLink>
                          <Link
                            to={`/${this.props.category}/${subCategory}/${category[subCategory][item].name}`}
                            activeStyle={{ color: '#FFFFFF' }}
                            onClick={() => {
                              this.props.closeOnItemClick(this.props.category);
                            }}
                          >
                            {category[subCategory][item].name}
                          </Link>
                        </ListLink>
                      </li>
                    ))
                  }
                </List>
                <LockButtonWrapper onClick={this.props.handleMenuLock}>
                  {menuLockButton}
                </LockButtonWrapper>
              </div>
            );
          })
        }
      </Sidebar>
    );
  }
}

PushMenu.propTypes = {
  category: PropTypes.any,
  closeOnItemClick: PropTypes.func,
  currentPage: PropTypes.func,
  handleMenuLock: PropTypes.func,
  menuLocked: PropTypes.bool,
  visible: PropTypes.bool,
};

export default PushMenu;

Автор: StuffedPoblano Источник Размещён: 08.11.2017 10:40

Ответы (2)


1 плюс

1034 Репутация автора

You can change your handlePageClick method to setState only when this.state.menuLocked is false.

  handlePageClick = () => {
    if (!this.state.menuLocked) {
      this.setState({
        menuOpen: false,
      });
    }
  }

Автор: Max Размещён: 08.11.2017 11:17

1 плюс

120 Репутация автора

Решение

Inside of handlePageClick() you should do a check to see if this.state.menuLocked is true. If so, don't change the value of menuOpen in state.

handlePageClick = () => {
  if (!this.state.menuLocked) {
    this.setState({
      menuOpen: false,
    });
  }
}

As a side note, in handleMenuLock() you are using the previous value of menuLocked to set the new value. Since setState is asynchronous, it's entirely possible that the value of menuLocked has changed by the time it actually saves and so you may not get the desired result. As such, you should pass it a function like this:

handleMenuLock = () => {
  this.setState((prevState) => ({ menuLocked: !prevState.menuLocked }))
}

This ensures that the value is actually toggled. Docs on using setState in this manner can be found here.

Автор: Steve Hawkins Размещён: 08.11.2017 11:18
Вопросы из категории :
32x32