Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React: Create onClick HOC without using an additional <div />

I would like to avoid manually adding the onClick property to my custom components.

For that, I thought about a Higher Order Component named WithClick that would wrap my components with the integrated onClick property.

The problem I'm facing is that in order to wrap it, I have to use an additional <div /> tag to access the event property. And this tag is messing up my CSS.

Example :

import React, { Component } from 'react'

const WithClick = (WrappedComponent) => {
  class BaseComponent extends Component {
    render () {
      return (
        <div onClick={this.props.onClick}>
          <WrappedComponent {...this.props} />
        </div>
      )
    }
  }

  return BaseComponent
}

export default WithClick

The solution would be a hack, allowing to attach an onClick event to a <React.Fragment /> tag or something similar.

I tried attaching ref to the child, but it doesn't work, I have to treat the ref prop in the child so there's no point doing that.

Do you know a workaround ?

like image 411
BiasInput Avatar asked Feb 04 '19 17:02

BiasInput


1 Answers

While I'm also a little skeptical of the need for this, I could see some specific case where you are adding the same handler to a lot of components and it would be necessary.

ReactDOM.findDOMNode is discouraged by the docs, and deprecated in strict mode. React.cloneElement is a better option.

const addClickToComponent = ({component}) => (
  React.cloneElement(component, {
    onClick: someComplicatedClickFunction,
  }
);

const ComponentWithClick = addClickToComponent(noClickComponent);

I usually make these wrapper components rather than HOC, and if you need to add a property to multiple children, you can do that.

const ClickWrapper = ({children}) => (
  <React.Fragment>
    {React.Children.map(children, child => (
      React.cloneElement(child, {
       onClick: someComplicatedClickFunction,
      )
     )
    }
  </React.Fragment>
 );

 // jsx

 <ClickWrapper>
   <ChildComponent />
   <ChildComponent />
   <ChildComponent />
 </ClickWrapper>
like image 152
JustH Avatar answered Oct 11 '22 09:10

JustH