【问题标题】:Refactor HOC as hook将 HOC 重构为钩子
【发布时间】:2019-11-08 14:14:52
【问题描述】:

在我花时间在 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 只是为了给组件添加一些预定义的空间。

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

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

【问题讨论】:

    标签: javascript reactjs react-hooks high-order-component


    【解决方案1】:

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

    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 组件。

    【讨论】:

      猜你喜欢
      • 2021-12-23
      • 2018-09-09
      • 1970-01-01
      • 2020-09-26
      • 1970-01-01
      • 2020-10-04
      • 2020-07-24
      • 2019-08-08
      • 2021-06-30
      相关资源
      最近更新 更多