3

在我花时间在 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 的最佳方法是什么?

4

1 回答 1

2

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

React Hooks 引入了几个新特性来响应它的基于类的对应物。useState补充this.statedocs)作为在渲染之间存储状态的功能性方式。useEffect补充了componentDidMountandcomponenetDidUnmount方法(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 组件。

于 2019-06-26T16:25:34.390 回答