Ali Jarbawi
Ali Jarbawi

Reputation: 27

Adding event handlers dynamically based on className

I have a React function component, where I get another component in props. Something like this:

function ChildComponent({cmp}) {
    // Here onClick handlers should be added [for example:
    // () => console.log("clicked")] to all
    // elements in cmp of class .clickable

    return ...
}

function ParentComponent() {
    return (
        <ChildComponent cmp={<div><button>Non-clickable</button><button className="clickable">Clickable</button></div>} />
    )
}

So how to add event handlers dynamically to elements with class clickable in the cmp props variable in the ChildComponent? Thank you in advance for your help.

Upvotes: 0

Views: 88

Answers (1)

junwen-k
junwen-k

Reputation: 3644

This uses Children API that allows you to modify children's props based on its current props. The ChildComponent will first loop through its current children, look for clickable className props and add onClick handler to its props.

The recursion loop allows nested children to work too.

function ChildComponent({ cmp }) {
  const handleOnClick = () => {
    alert("Clicked");
  };

  const childrenMap = (child) => {
    if (child.props) {
      const newProps = Object.assign({}, child.props);
      const { children, className } = newProps;
      if (className && className.split(' ').some(cn => cn === 'clickable')) {
        newProps.onClick = handleOnClick;
      }
      if (children) {
        newProps.children = Children.map(children, childrenMap);
      }
      return cloneElement(child, newProps);
    }
    return child;
  }

  return Children.map(cmp, childrenMap);
}

function ParentComponent() {
  return (
    <ChildComponent
      cmp={(
        <div>
          <button>Non-clickable</button>
          <div>
            <div>
              <button className="clickable">Clickable</button>
            </div>
          </div>
          <button className="clickable">Clickable</button>
        </div>
      )}
    />
  );
}

Upvotes: 1

Related Questions