0

I'm trying to implement a drop down wrapper. The element wrapped by the DropDownWrapper is expected to toggle the display of drop-down through onClick.

class DropdownMenuWrapper extends React.Component {
constructor(props) {
    super(props);
    this.state = {
      active: true,
    };

    this.handleDropDownDisplay = this.handleDropDownDisplay.bind(this);
    this.displayDropDownItems = this.displayDropDownItems.bind(this);
  }

  displayDropDownItems(menuItems, onSelectMenuItem, children) {
    return (
      menuItems.map(item => (
        <a
          className={cx('navItem')}
          key={item.value}
          onClick={() => onSelectMenuItem(children)}
        >
         {item.logo}
         {item.display}
       </a>
     ))
   );
 }

  handleDropDownDisplay() {
    this.setState({
      active: !this.state.active,
    });
  }

  render() {
    const {
      className, menuItems, onSelectMenuItem, children, label,
    } = this.props;
    return (
      <div>
        {children}
        <nav className={className} aria-label={label}>
          {this.state.active && this.displayDropDownItems(menuItems, onSelectMenuItem, children)}
        </nav>
      </div>
    );
  }
}

export default DropdownMenuWrapper;

Here I want to achieve dropdown toggle on the wrapped button below

<DropdownMenuWrapper
  menuItems={[
    { value: 'dashboard', display: 'Dashboard' },
    { value: 'myProfile', display: 'My Profile' },
  ]}
>
  <Button />
</DropdownMenuWrapper>

Is there a way I can use {children} onClick to change the state of the Parent component (DropdownMenuWrapper) in this case?

ian
  • 1
  • 1
  • You can pass an onClick prop to the children, something like: https://stackoverflow.com/questions/32370994/how-to-pass-props-to-this-props-children – Timh Sep 05 '18 at 20:51
  • why DropdownMenuWrapper is so complicated? it shouldn't be like this – Jalal Sep 05 '18 at 20:54
  • Possible duplicate of [How to update parent's state in React?](https://stackoverflow.com/questions/35537229/how-to-update-parents-state-in-react) – Jonast92 Sep 05 '18 at 20:57

2 Answers2

0

Thankfully this problem has been solved on various platforms, including this one. I'd like to get you started:

You can pass a function from the parent component down to the child component via its props and from there use it to alter the parent component's state.

The function, defined in the parent component, takes care of updating the parent component's state. The child component must then bind the function to an event that takes place in the child component and once the event is triggered the function takes place in the parent component and does the change it's implemented to do.

You can see a detailed code implementation in an already existing answer here: How to update parent's state in React?. Pardon me if this is not what you're looking for, in that case you should make your question more clear.

In the future you should try to search for an existing answer since there's a good chance the problem has been solved. A simple search engine search did the job for me and I like to tag Stack overflow as a part of the search query for a higher chance of a good answer.

Jonast92
  • 4,964
  • 1
  • 18
  • 32
0

This helped me out reference: https://reactjs.org/docs/react-api.html#reactchildren

class DropdownMenuWrapper extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      active: false,
    };
  }

  displayDropDownItems = (menuItems, onSelectMenuItem) => (
    menuItems.map(item => (
      <a
        className={cx('navItem')}
        key={item.value}
        onClick={() => onSelectMenuItem(item.value)}
      >
        { item.icon && <span className={cx('icon')}>{item.icon}</span>} {item.display}
      </a>
    ))
  );

  toggleDropDown = () => {
    this.setState({
      active: !this.state.active,
    });
  };

  render() {
    const {
      className, menuItems, onSelectMenuItem, children, label,
    } = this.props;

    const childrenWithProps = React.Children.map(children, child =>
      React.cloneElement(child, { toggleDropDown: this.toggleDropDown }));

    return (
      <div>
        {childrenWithProps}
        <nav className={className} aria-label={label}>
          {this.state.active && this.displayDropDownItems(menuItems, onSelectMenuItem, children)}
        </nav>
      </div>);
  }
}

export default DropdownMenuWrapper;
ian
  • 1
  • 1