繁体   English   中英

将 HOC 重构为钩子

[英]Refactor HOC as hook

在我花在 react 和几篇文章上的时间里,我问自己如何将 HOC 重构为钩子,以及它是否有用以及为什么,

这是一个重构的小组件

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;

根据官方文档:

Hooks 会取代渲染道具和高阶组件吗?

通常,渲染道具和高阶组件仅渲染一个子组件。 我们认为 Hooks 是一种更简单的方法来服务于这个用例。 这两种模式仍有一席之地(例如,虚拟滚动组件可能有一个 renderItem 道具,或者可视化容器组件可能有自己的 DOM 结构)。 但在大多数情况下,Hooks 就足够了,可以帮助减少树中的嵌套。

我使用这个 HOC 只是为了向组件添加一些预定义的空间。

将它重构为钩子会更好,你能解释一下为什么吗?

如果是,那么将其重构为 hook 的最佳方法是什么?

TDLR; 因为您的 HOC 没有任何状态或订阅,所以没有正当理由使用钩子重构您的组件。

React Hooks 引入了几个新特性来作为 React Hooks 的补充,以补充其基于类的对应物。 useState补充this.state ( docs ) 作为在渲染之间存储状态的功能方式。 useEffect补充了componentDidMountcomponenetDidUnmount方法 ( 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} />;
    }
  };
}

并将其转换为功能组件,您可能会得到如下结果:

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} />;
}

您的填充和间距在每次渲染时都会重新生成。 由于您的问题中的代码在渲染之间没有任何持久性,因此尝试将其重构为实现 React Hooks 的组件没有多大意义。 React Hooks 更适合将基于类的 React 组件转换为功能性的 React 组件。

暂无
暂无

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

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