可复用 React 的 HOC 以及的 Render Props

重复是不可能的,这辈子都不可能写重复的代码

当然,这句话分分钟都要被产品(领导)打脸,真的最后一次改需求,我们烦恼于频繁修改的需求

虽然我们不能改变别人,但我们却可以尝试去做的更好,我们需要抽象,封装重复的功能或者逻辑,而不是老旧的重复着机械的复制粘贴修改

那么我们如何去封装 React 中的组件以及逻辑呢?

这次我们来讲讲 React 里的高级组件

React 高级组件有两种方式:

  1. 使用高阶组件( Higher Order Component ==> HOC )
  2. 子组件作为函数的模式( Render Props )

高阶组件

首先来说说高阶组件,它不是 React 的提供的 API,它是模式,一种增强组件的模式,简单来说其实就是高阶函数,高阶函数大家应该不陌生

高阶函数 : 把函数作为参数传入,返回一个新的函数,这样的函数称为高阶函数

而所谓的高阶组件也就是传入一个现有组件作为参数,返回一个新的组件,高阶租价也分为代理方式和继承方式
我们先来看看一个简单的 HOC :

import React from 'react';

function addNameProp(WrapperComponent) {
  return class extends React.Component {
    render() {
      const { name, ...props } = this.props;
      return <WrapperComponent {...props} name={name || 'cnyballk'} />;
    }
  };
}

export default addNameProp;

在上面的代码里我们定义了一个 addNameProp。 函数,它的作用就是为没有传入 name 的 prop 传入的组件添加一个 name 的 prop ,然后渲染出来

这个高阶组件就完成了对传入组件的增强,这也是一个代理方式的高阶组件

那么继承方式是怎么样的呢

import React from 'react';

function addNameProp(WrapperComponent) {
  return class extends WrapperComponent {
    render() {
      this.props = {
        ...this.props,
        name: this.props.name || 'cnyballk',
      };
      return super.render();
    }
  };
}

export default addNameProp;

和上面的高阶组件 一样的效果,而继承模式和代理模式最大的区别就是一个是返回传入的组件,一个是调用继承的父组件的 render 方法

⚠️ 在代理模式下 WrapperComponent 经历了完整的生命周期,返回的组件也有一次完整的生命周期,而继承模式 则是调用了 WrapperComponent 的 render ,只有返回的组件的一个生命周期

如果我们用过 react-redux 的 connect 也就知道 connect 也是一个代理模式的高阶组件

⚠️ 高阶组件可以这么使用

@Wrapper
class Index extends Component {
   ...略
}

emmmm...这个涉及到 js 的装饰器,各位自己去搜来学习哈

Render Props

那么我们已经认识了高阶组件的重用方法,也认识到了高阶组件的优点。

但是高阶组件的缺点是什么呢?

相信你们也能看到了,我们传递一个 name 的 Prop ,那是不是得传入的组件能够处理才可以,而且还有命名的冲突危险,毕竟有些组件的 props 命名各有不同,或者说子组件需要同一份数据处理方式却不一样,所以说这个时候就不适用 HOC 了

HOC 对于使用者来说是一个黑盒,还需要去看他们的实现

而 Render Props 则是 数据给你,其他的你自己来
我们来看一个简单的例子

import React from 'react';

class AddNameProp extends React.Component {
  render() {
    const name = 'cnyballk';
    return this.props.children(name);
  }
}

export default AddNameProp;

简单的使用

<AddNameProp>{name => <div>我叫 {name}</div>}</AddNameProp>

想传递给组件

<AddNameProp>
  {name =>
    <Hello name={name}/>;
  }
</AddNameProp>

或者是其他的 prop 名

<AddNameProp>
  {name =>
    <Hello myName={name}/>;
  }
</AddNameProp>

我们可以看到,这个方式很灵活,因为子组件是一个函数,一切皆有可能,但是 Render Props 也有缺点就是难以做性能优化,高阶组件可以利用 SCU 来避免重复渲染。虽然这样,,Render Props 却是一个非常好(牛逼)的一个模式,我很喜欢

Render Props VS HOC

我们能够清楚的明白,HOC是一种粗粒度的代码复用,而Render Props是一种细粒度的复用,他们可以互换,我们什么时候用HOC,什么时候用Render Props相信大家也差不多清楚了

小结

本文介绍了 React 的高级组件的两个方式,各有优缺点,但它们都是为了重用代码,我们可以自己选择喜欢的模式去做,但是不要复制粘贴了,感受封装复用的力量

高阶组件代理模式可以更好的控制和实现,继承模式则可以控制特定组件的生命周期,与高阶组件相比, Render Props 模式更加灵活,有函数,我们可以更自由

posted @ 2018-07-15 14:18  云剪者  阅读(1836)  评论(0编辑  收藏