Vue 进阶必学之高阶组件 HOC(冲击20k必备)

前言


  • 高阶组件这个概念在 React 中一度非常流行,但是在 Vue 的社区里讨论的不多,本篇文章就真正的带你来玩一个进阶的骚操作。

  • 先和大家说好,本篇文章的核心是学会这样的思想,也就是 智能组件 和 木偶组件 的解耦合,没听过这个概念没关系,下面会详细说明。

  • 这可以有很多方式,比如 slot-scopes,比如未来的composition-api。本篇所写的代码也不推荐用到生产环境,生产环境有更成熟的库去使用,这篇强调的是 思想,顺便把 React 社区的玩法移植过来皮一下。

  • 不要喷我,不要喷我,不要喷我!! 此篇只为演示高阶组件的思路,如果实际业务中想要简化文中所提到的异步状态管理,请使用基于 slot-scopes 的开源库 vue-promised

  • 另外标题中提到的 20k 其实有点标题党,我更多的想表达的是我们要有这样的精神,只会这一个技巧肯定不能让你达到 20k。但我相信只要大家有这样钻研高级用法,不断优化业务代码,不断提效的的精神,我们总会达到的,而且这一天不会很远。

我的web前端学习交流群点击进入1045267283,欢迎加入!

例子

 本文就以平常开发中最常见的需求,也就是异步数据的请求为例,先来个普通玩家的写法:
 <template>
    <div v-if="error">failed to load</div>
    <div v-else-if="loading">loading...</div>
    <div v-else>hello {
  {result.name}}!</div>
</template>

<script>
export default {
  data() {
    return {
        result: {
          name: '',
        },
        loading: false,
        error: false,
    },
  },
  async created() {
      try {
        // 管理loading
        this.loading = true
        // 取数据
        const data = await this.$axios('/api/user')  
 this.data = data
      } catch (e) {
        // 管理error
        this.error = true  
      } finally {
        // 管理loading
        this.loading = false
      }
  },
}
</script>

  • 一般我们都这样写,平常也没感觉有啥问题,但是其实我们每次在写异步请求的时候都要有 loading、 error 状态,都需要有 取数据 的逻辑,并且要管理这些状态。

  • 那么想个办法抽象它?好像特别好的办法也不多,React 社区在 Hook 流行之前,经常用 HOC(high order component) 也就是高阶组件来处理这样的抽象。

高阶组件是什么?

  • 说到这里,我们就要思考一下高阶组件到底是什么概念,其实说到底,高阶组件就是:
  • 一个函数接受一个组件为参数,返回一个包装后的组件

在 React 中

  • 在 React 里,组件是 Class,所以高阶组件有时候会用 装饰器 语法来实现,因为 装饰器 的本质也是接受一个 Class 返回一个新的 Class
  • 在 React 的世界里,高阶组件就是 f(Class) -> 新的Class

在 Vue 中


  • 在 Vue 的世界里,组件是一个对象,所以高阶组件就是一个函数接受一个对象,返回一个新的包装好的对象。

  • 类比到 Vue 的世界里,高阶组件就是 f(object) -> 新的object

智能组件和木偶组件


  • 如果你还不知道 木偶 组件和 智能 组件的概念,我来给你简单的讲一下,这是 React 社区里一个很成熟的概念了。

  • 木偶 组件: 就像一个牵线木偶一样,只根据外部传入的 props 去渲染相应的视图,而不管这个数据是从哪里来的。

  • 智能 组件: 一般包在 木偶 组件的外部,通过请求等方式获取到数据,传入给 木偶 组件,控制它的渲染。


一般来说,它们的结构关系是这样的:

<智能组件>
<木偶组件 />
</智能组件>


它们还有另一个别名,就是 容器组件 和 ui组件,是不是很形象。

实现


具体到上面这个例子中(如果你忘了,赶紧回去看看,哈哈),我们的思路是这样的,

  1. 高阶组件接受 木偶组件 和 请求的方法 作为参数
  2. 在 mounted 生命周期中请求到数据
  3. 把请求的数据通过 props 传递给 木偶组件
  • 接下来就实现这个思路,首先上文提到了,HOC 是个函数,本次我们的需求是实现请求管理的 HOC,那么先定义它接受两个参数,我们把这个 HOC 叫做 withPromise

  • 并且 loadingerror 等状态,还有 加载中加载错误 等对应的视图,我们都要在 新返回的包装组件 ,也就是下面的函数中 return 的那个新的对象 中定义好。
const withPromise = (wrapped, promiseFn) => {
  return {
    name: "with-promise",
    data() {
      return {
        loading: false,
        error: false,
        result: null,
      };
    },
    async mounted() {
      this.loading = true;
      const result = await promiseFn().finally(() => {
        this.loading = false;
      });
      this.result = result;
    },
  };
};


  • 0
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值