简体   繁体   English

将 HOC 重构为钩子

[英]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,在我花在 react 和几篇文章上的时间里,我问自己如何将 HOC 重构为钩子,以及它是否有用以及为什么,

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? Hooks 会取代渲染道具和高阶组件吗?

Often, render props and higher-order components render only a single child.通常,渲染道具和高阶组件仅渲染一个子组件。 We think Hooks are a simpler way to serve this use case.我们认为 Hooks 是一种更简单的方法来服务于这个用例。 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).这两种模式仍有一席之地(例如,虚拟滚动组件可能有一个 renderItem 道具,或者可视化容器组件可能有自己的 DOM 结构)。 But in most cases, Hooks will be sufficient and can help reduce nesting in your tree.但在大多数情况下,Hooks 就足够了,可以帮助减少树中的嵌套。

I use this HOC just to add some predefined space to a component.我使用这个 HOC 只是为了向组件添加一些预定义的空间。

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 ?如果是,那么将其重构为 hook 的最佳方法是什么?

TDLR; TDLR; Because your HOC doesn't have any state or subscriptions, there wouldn't be a valid reason to refactor your component with hooks.因为您的 HOC 没有任何状态或订阅,所以没有正当理由使用钩子重构您的组件。

React Hooks introduce several new features to react to complement its class-based counterparts. React Hooks 引入了几个新特性来作为 React Hooks 的补充,以补充其基于类的对应物。 useState complements this.state ( docs ) as a functional way to store state between renders. useState补充this.state ( docs ) 作为在渲染之间存储状态的功能方式。 useEffect complements the componentDidMount and componenetDidUnmount methods ( docs ) which provides a way to perform both setup and tear down of a functional react component. useEffect补充了componentDidMountcomponenetDidUnmount方法 ( docs ),它提供了一种方法来执行功能性反应组件的设置和拆除。

If you took a HOC like this one from the docs:如果您从文档中获取了这样的 HOC:

// 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 的组件没有多大意义。 React Hooks are more suitable for converting class-based React components to functional React components. React Hooks 更适合将基于类的 React 组件转换为功能性的 React 组件。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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