简体   繁体   中英

Refactor HOC as hook

during my time spent on react and on several articles I'm asking to my self how to refactor an HOC as hook, and if it would be usefull and why,

This is a little component to refactor

function withSpacing(Component) {
  const WrappedWithSpacing = ({
    pv, ph, pt, pb, pl, pr, style, ...props
  }) => {

    const styleWithSpacing = {};

    const spacing = layout.padding;

    const paddingTop = pt || pv;
    const paddingBottom = pb || pv;
    const paddingRight = pr || ph;
    const paddingLeft = pl || ph;

    if(paddingTop > 0) styleWithSpacing.paddingTop = paddingTop * spacing;
    if(paddingBottom > 0) styleWithSpacing.paddingBottom = paddingBottom * spacing;
    if(paddingLeft > 0) styleWithSpacing.paddingLeft = paddingLeft * spacing;
    if(paddingRight > 0) styleWithSpacing.paddingRight = paddingRight * spacing;

    return <Component style={{...style, ...styleWithSpacing}} {...props} /> 
  }

  WrappedWithSpacing.propTypes = {
    pv: PropTypes.number,
    ph: PropTypes.number,
    pt: PropTypes.number,
    pb: PropTypes.number,
    pl: PropTypes.number,
    pr: PropTypes.number,
    style: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
  }

  WrappedWithSpacing.defaultProps = {
    pv: 0,
    ph: 0,
    pt: 0,
    pb: 0,
    pr: 0,
    pl: 0,
  }

  return WrappedWithSpacing;
}

export default withSpacing;

according to the official documentation:

Do Hooks replace render props and higher-order components?

Often, render props and higher-order components render only a single child. We think Hooks are a simpler way to serve this use case. There is still a place for both patterns (for example, a virtual scroller component might have a renderItem prop, or a visual container component might have its own DOM structure). But in most cases, Hooks will be sufficient and can help reduce nesting in your tree.

I use this HOC just to add some predefined space to a component.

it would be really better to refactor this as hook, could you please explain me why ?

if yes, what will be the best way to refactor this as hook ?

TDLR; Because your HOC doesn't have any state or subscriptions, there wouldn't be a valid reason to refactor your component with hooks.

React Hooks introduce several new features to react to complement its class-based counterparts. useState complements this.state ( docs ) as a functional way to store state between renders. useEffect complements the componentDidMount and componenetDidUnmount methods ( docs ) which provides a way to perform both setup and tear down of a functional react component.

If you took a HOC like this one from the docs:

// This function takes a component...
function withSubscription(WrappedComponent, selectData) {
  // ...and returns another component...
  return class extends React.Component {
    constructor(props) {
      super(props);
      this.handleChange = this.handleChange.bind(this);
      this.state = {
        data: selectData(DataSource, props)
      };
    }

    componentDidMount() {
      // ... that takes care of the subscription...
      DataSource.addChangeListener(this.handleChange);
    }

    componentWillUnmount() {
      DataSource.removeChangeListener(this.handleChange);
    }

    handleChange() {
      this.setState({
        data: selectData(DataSource, this.props)
      });
    }

    render() {
      // ... and renders the wrapped component with the fresh data!
      // Notice that we pass through any additional props
      return <WrappedComponent data={this.state.data} {...this.props} />;
    }
  };
}

And converted it to a functional component, you would likely end up with something like this:

function withSubscription(WrappedComponent, selectData) {
  return function WrappedComponent (props) {
    const [myData, setMyData] = useState(null);

       useEffect(() => {
         const handleMyDataChange = newData => {
           setMyData(newData);
         }

         DataSource.addChangeListener(handleMyDataChange);

         return function cleanup() {
           DataSource.removeChangeListener(handleMyDataChange);
         };
       });

      return <WrappedComponent data={data} {...this.props} />;
}

Your padding and spacing get re-generated on every render. Since the code you have in your question doesn't have anything that persists between renders, it wouldn't make much sense to attempt to refactor it into a component that implements React Hooks. React Hooks are more suitable for converting class-based React components to functional React components.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM