首页 web前端 js教程 React给Vue引入容器组件有哪些方法

React给Vue引入容器组件有哪些方法

May 14, 2018 am 11:50 AM
react 哪些 组件

这次给大家带来React给Vue引入容器组件有哪些方法,React给Vue引入容器组件的注意事项有哪些,下面就是实战案例,一起来看一下。

如果你使用过 Redux 开发 React,你一定听过 容器组件(Smart/Container Components) 或 展示组件(Dumb/Presentational Components),这样划分有什么样的好处,我们能否能借鉴这种划分方式来编写 Vue 代码呢?这篇文章会演示为什么我们应该采取这种模式,以及如何在 Vue 中编写这两种组件。

为什么要使用容器组件?

假如我们要写一个组件来展示评论,在没听过容器组件之前,我们的代码一般都是这样写的:

components/CommentList.vue

<template>
 <ul>
 <li v-for="comment in comments"
  :key="comment.id"
 >
  {{comment.body}}—{{comment.author}}
 </li>
 </ul>
</template>
<script>
export default {
 name: 'CommentList',
 computed: {
 comments () {
  return this.$store.state.comments
 }
 },
 mounted () {
 this.$store.dispatch('fetchComments')
 }
}
</script>
登录后复制

store/index.js

import Vue from 'vue';
import Vuex from 'vuex';
登录后复制

Vue.use(Vuex);

const store = new Vuex.Store({
 state: {
 comments: [],
 },
 mutations: {
 setComments(state, comments) {
  state.comments = comments;
 },
 },
 actions: {
 fetchComments({commit}) {
  setTimeout(() => {
  commit('setComments', [
   {
   body: '霸气侧漏',
   author: '雷叔',
   id: 1123,
   },
   {
   body: '机智如我',
   author: '蕾妹',
   id: 1124,
   },
  ]);
  });
 },
 },
});
登录后复制

export default store;

这样写看起来理所当然,有没有什么问题,或者可以优化的地方呢?

有一个很显而易见的问题,由于 CommentList.vue 与 项目的 Vuex store 产生了耦合,导致脱离当前的项目很难复用。

有没有更好的组件的组织方式,可以解决这个问题呢?是时候了解下 React 社区的容器组件的概念了。

什么是容器组件

在 React.js Conf 2015 ,有一个 Making your app fast with high-performance components 的主题介绍了容器组件。

 

容器组件专门负责和 store 通信,把数据通过 props 传递给普通的展示组件,展示组件如果想发起数据的更新,也是通过容器组件通过 props 传递的回调函数来告诉 store。

由于展示组件不再直接和 store 耦合,而是通过 props 接口来定义自己所需的数据和方法,使得展示组件的可复用性会更高。

容器组件 和 展示组件 的区别


     展示组件
容器组件
作用 描述如何展现(骨架、样式) 描述如何运行(数据获取、状态更新)
直接使用 store
数据来源 props 监听 store state
数据修改 从 props 调用回调函数 向 store 派发 actions

来自 Redux 文档 https://user-gold-cdn.xitu.io/2018/5/2/1631f590aa5512b7

用 容器组件/展示组件 模式改造上面的例子

针对最初的例子,如何快速按照这种模式来划分组件呢?我们主要针对 CommentList.vue 进行拆分,首先是基本的概要设计:

概要设计

展示组件

components/CommentListNew.vue 这是一个新的评论展示组件,用于展示评论
comments: Array prop 接收以 { id, author, body } 形式显示的 comment 项数组。
fetch() 接收更新评论数据的方法
展示组件只定义外观并不关心数据来源和如何改变。传入什么就渲染什么。

comments、fetch 等这些 props 并不关心背后是否是由 Vuex 提供的,你可以使用 Vuex,或者其他状态管理库,甚至是一个 EventBus,都可以复用这些展示组件。

同时,可以利用 props 的类型和验证来约束传入的内容,比如验证传入的 comments 是否是一个含有指定字段的对象,这在之前混合组件的情况是下是没有的,提高了代码的健壮性。

容器组件

containers/CommentListContainer.vue 将 CommentListNew 组件连接到 store
容器组件可以将 store 对应的 state 或者 action 等封装传入展示组件。

编码实现

Talk is cheap, show me the code!
components/CommentListNew.vue

这个文件不再依赖 store,改为从 props 传递。

值得注意到是 comments 和 fetch 分别定义了 type 、default 和 validator,用以定义和验证 props。

<template>
 <ul>
 <li v-for="comment in comments"
  :key="comment.id"
 >
  {{comment.body}}—{{comment.author}}
 </li>
 </ul>
</template>
<script>
export default {
 name: 'CommentListNew',
 props: {
 comments: {
  type: Array,
  default () {
  return []
  },
  validator (comments) {
  return comments.every(comment =>
   'body' in comment &&
   'author' in comment &&
   'id' in comment
  )
  }
 },
 fetch: {
  type: Function,
  default: () => {}
 }
 },
 mounted () {
 this.fetch()
 }
}
</script>
登录后复制

containers/CommentListContainer.vue

容器组件的职责

通过 computed 来获取到状态更新,传递给展示组件

通过 methods 定义回调函数,回调函数内部调用 store 的 dispatch 方法,传递给展示组件

<template>
 <CommentList
 :comments="comments"
 :fetch="fetchComments"
 ></CommentList>
</template>
<script>
import CommentList from '@/components/CommentListNew'
export default {
 name: 'CommentListContainer',
 components: {
 CommentList
 },
 computed: {
 comments () {
  return this.$store.state.comments
 }
 },
 methods: {
 fetchComments () {
  return this.$store.dispatch('fetchComments')
 }
 }
}
</script>
登录后复制

使用 @xunlei/vuex-connector 实现容器组件

上面演示的容器组件的代码非常简单,实际上如果直接投入生产环境,会产生一些问题。

手动实现容器组件存在的不足

代码比较繁琐

在上面的例子中,每次传递一个 state 都要定义一个 computed,每传递一个 mutation 或者 action 都需要定一个方法,而且还要注意这个方法的参数要透传过去,同时还要处理返回值,比如异步的 action 需要返回 promise 的时候,定义的这个 method 也得把 action 的返回值返回出去。

无法透传其他 props 给展示组件

比如展示组件新增了一个 prop 叫做 type,可以传递一个评论的类型,用来区分是热门还是最新,如果用上面的容器实现方式,首先需要在容器组件这层新增一个 prop 叫做 type 接受外部传来的参数,然后在展示组件内部同样定义一个 叫做 type 的 prop,然后才能传递下去。

需要透传的 prop 必须定义两遍,增加了维护的成本。

<CommentListContainer type="热门"></CommentListContainer>
<CommentList
 :fetch="fetchComments"
 :comments="comments"
 :type="type"
 ></CommentList>
登录后复制

容器组件无法统一进行优化

每一个手动实现的容器组件实质上代码逻辑非常近似,但是没有经过同一层封装,如果目前实现的容器组件存在一些性能优化的地方,需要每个容器组件都进行统一的修改。

无法控制展示组件不去获取 store

因为容器组件是通过 this.$store 获取 store 的,展示组件内部实质上也可以直接跟 store 通信,如果没有约束,很难统一要求展示组件不得直接和 store 通信。

使用 @xunlei/vuex-connector

@xunlei/vuex-connector 借鉴了 react redux 的 connect 方法,在 vuex 基础上进行的开发。

有以下几个特点:

代码非常简洁

下面是上面例子中手动实现的容器组件的改造版本:

comonents/ConnectCommentListContainer.vue

<script>
import CommentListNew from '@/components/CommentListNew'
import { connector } from '@/store'
export default connector.connect({
 mapStateToProps: {
  comments: (state) => state.comments
 },
 mapActionToProps: {
  fetch: 'fetchComments'
 }
})(CommentListNew)
</script>
登录后复制

通过 connector 的 connnect 方法,传入要映射的配置,支持 mapStateToProps, mapGettersToProps, mapDispatchToProps, mapCommitToProps 这四种,每一种都是只要配置一个简单的 map 函数,或者字符串即可。

然后在返回的函数中传入要连接的展示组件,是不是非常的简洁,同时借鉴了 redux 优雅的函数式风格。

问题来了,connector 是什么?

connector 实际上是一个能获取到 store 实例的连接器,可以在初始化 vuex store 的时候进行初始化。

import Vue from 'vue';
import Vuex from 'vuex';
import VuexConnector from '@xunlei/vuex-connector';
Vue.use(Vuex);
const store = new Vuex.Store({
 // your store
});
export const connector = new VuexConnector(store);
export default store;
登录后复制

一个 Vue 程序实际上只需要初始化一次即可。

支持透传其他 props 给展示组件

VuexConnector 实现的时候采用了函数式组件( functional: true )

函数式组件是无状态 (没有响应式数据),无实例 (没有 this 上下文)。

在作为包装组件时函数式组件非常有用,比如,当你需要做这些时:

程序化地在多个组件中选择一个

在将 children, props, data 传递给子组件之前操作它们。

另外,函数式组件只是一个函数,所以渲染开销也低很多。然而,对持久化实例的缺乏也意味着函数式组件不会出现在 Vue devtools 的组件树里。

因此需要透传的 props 可以直接透传,需要通过 map 方式从 store 里进行获取的 props 直接会根据配置生成。

统一封装方便后续统一优化

VuexConnector.connect 方法将本来需要重复做的事情进行了抽象,也带来了后期进行统一优化和升级的便利。

可以控制展示组件无法直接与 store 通信

VuexConnector 不依赖 this.$store,而是依赖初始化传入的 store 实例,容器组件可以用 connect 将展示组件与 store 进行连接。

由于不依赖 this.$store,我们在程序入口 new Vue 的时候,就不需要传入 store 实例了。

比如,之前我们是通过下面的方式进行初始化:

import Vue from 'vue';
import App from './App';
import store from './store';
new Vue({
 el: '#app',
 components: {App},
 template: '<App/>',
 store,
});
登录后复制

使用了 VuexConnector 之后,在最初 new Vue 的时候就不需要也最好不要传递 store 了,这样就避免了 this.$store 泛滥导致代码耦合的问题。

引入容器组件/展示组件模式带来的好处

可复用性

容器组件/展示组件的划分,采用了单一职责原则的设计模式,容器组件专门负责和 store 通信,展示组件只负责展示,解除了组件的耦合,可以带来更好的可复用性。

健壮性

由于展示组件和容器组件是通过 prop 这种接口来连接,可以利用 props 的校验来增强代码的可靠性,混合的组件就没有这种好处。

另外对 props 的校验可以采取一下几种方式:

Vue 组件 props 验证

可以验证 props 的类型,默认可以校验是否是以下类型:

  • String

  • Number

  • Boolean

  • Function

  • Object

  • Array

  • Symbol

如果你的 props 是类的一个实例,type 也可以是一个自定义构造器函数,使用 instanceof 检测。

如果还是不满足需求,可以自定义验证函数:

// 自定义验证函数
propF: {
 validator: function (value) {
  return value > 10
 }
}
登录后复制

TypeScript 类型系统

Vue 组件 props 验证对于对象或者其他复杂的类型校验还是不太友好,所以很多人也推荐大家的 props 尽量采取简单类型,不过如果你有在用 TypeScript 开发 Vue 应用,可以利用 TypeScript 静态类型检查来声明你的 props 。

@Component
export default class Hello extends Vue {
 @Prop
 info: IHelloInfo; // 这里可以用你自定义的 interface
}
登录后复制

可测试性

由于组件做的事情更少了,使得测试也会变得容易。

容器组件不用关心 UI 的展示,只关心数据和更新。

展示组件只是呈现传入的 props ,写单元测试的时候也非常容易 mock 数据层。

引入容器组件/展示组件模式带来的限制

学习和开发成本

因为容器组件/展示组件的拆分,初期会增加一些学习成本,不过当你看完这篇文章,基本上也就入门了。

在开发的时候,由于需要封装一个容器,包装一些数据和接口给展示组件,会增加一些工作量, @xunlei/vuex-connector 通过配置的方式可以减轻不少你的工作量。

另外,在展示组件内对 props 的声明也会带来少量的工作。

总体来说,引入容器组件/展示组件模式投入产出比还是比较值得的。

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

Node.Js实现端口重用步骤详解

Vue.js双向绑定实现步骤说明

以上是React给Vue引入容器组件有哪些方法的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
2 周前 By 尊渡假赌尊渡假赌尊渡假赌
仓库:如何复兴队友
4 周前 By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒险:如何获得巨型种子
4 周前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

如何利用React和WebSocket构建实时聊天应用 如何利用React和WebSocket构建实时聊天应用 Sep 26, 2023 pm 07:46 PM

如何利用React和WebSocket构建实时聊天应用引言:随着互联网的快速发展,实时通讯越来越受到人们的关注。实时聊天应用已经成为现代社交和工作生活中不可或缺的一部分。本文将介绍如何利用React和WebSocket构建一个简单的实时聊天应用,并提供具体的代码示例。一、技术准备在开始构建实时聊天应用之前,我们需要准备以下技术和工具:React:一个用于构建

React前后端分离指南:如何实现前后端的解耦和独立部署 React前后端分离指南:如何实现前后端的解耦和独立部署 Sep 28, 2023 am 10:48 AM

React前后端分离指南:如何实现前后端的解耦和独立部署,需要具体代码示例在当今的Web开发环境中,前后端分离已经成为一种趋势。通过将前端和后端代码分开,可以使得开发工作更加灵活、高效,并且方便进行团队协作。本文将介绍如何使用React实现前后端分离,从而实现解耦和独立部署的目标。首先,我们需要理解什么是前后端分离。传统的Web开发模式中,前端和后端是耦合在

如何安装Win10旧版本组件DirectPlay 如何安装Win10旧版本组件DirectPlay Dec 28, 2023 pm 03:43 PM

不少用户在玩win10的的一些游戏的时候总是会遇到一些问题,比如说卡屏和花屏等等情况,这个时候我们是可以采用打开directplay这个功能来解决的,而且功能的操作方法也很简单。win10旧版组件directplay怎么安装1、在搜索框里面输入“控制面板”然后打开2、查看方式选择大图标3、找到“程序和功能”4、点击左侧的启用或关闭win功能5、选择旧版这里的勾选上就可以了

如何利用React和Flask构建简单易用的网络应用 如何利用React和Flask构建简单易用的网络应用 Sep 27, 2023 am 11:09 AM

如何利用React和Flask构建简单易用的网络应用引言:随着互联网的发展,网络应用的需求也越来越多样化和复杂化。为了满足用户对于易用性和性能的要求,使用现代化的技术栈来构建网络应用变得越来越重要。React和Flask是两种在前端和后端开发中非常受欢迎的框架,它们可以很好的结合在一起,用来构建简单易用的网络应用。本文将详细介绍如何利用React和Flask

如何利用React和RabbitMQ构建可靠的消息传递应用 如何利用React和RabbitMQ构建可靠的消息传递应用 Sep 28, 2023 pm 08:24 PM

如何利用React和RabbitMQ构建可靠的消息传递应用引言:现代化的应用程序需要支持可靠的消息传递,以实现实时更新和数据同步等功能。React是一种流行的JavaScript库,用于构建用户界面,而RabbitMQ是一种可靠的消息传递中间件。本文将介绍如何结合React和RabbitMQ构建可靠的消息传递应用,并提供具体的代码示例。RabbitMQ概述:

如何利用React和Google BigQuery构建快速的数据分析应用 如何利用React和Google BigQuery构建快速的数据分析应用 Sep 26, 2023 pm 06:12 PM

如何利用React和GoogleBigQuery构建快速的数据分析应用引言:在当今信息爆炸的时代,数据分析已经成为了各个行业中不可或缺的环节。而其中,构建快速、高效的数据分析应用则成为了许多企业和个人追求的目标。本文将介绍如何利用React和GoogleBigQuery结合起来构建快速的数据分析应用,并提供详细的代码示例。一、概述React是一个用于构建

React代码调试指南:如何快速定位和解决前端bug React代码调试指南:如何快速定位和解决前端bug Sep 26, 2023 pm 02:25 PM

React代码调试指南:如何快速定位和解决前端bug引言:在开发React应用程序时,经常会遇到各种各样的bug,这些bug可能使应用程序崩溃或导致不正确的行为。因此,掌握调试技巧是每个React开发者必备的能力。本文将介绍一些定位和解决前端bug的实用技巧,并提供具体的代码示例,帮助读者快速定位和解决React应用程序中的bug。一、调试工具的选择:在Re

React Router使用指南:如何实现前端路由控制 React Router使用指南:如何实现前端路由控制 Sep 29, 2023 pm 05:45 PM

ReactRouter使用指南:如何实现前端路由控制随着单页应用的流行,前端路由成为了一个不可忽视的重要部分。ReactRouter作为React生态系统中最受欢迎的路由库,提供了丰富的功能和易用的API,使得前端路由的实现变得非常简单和灵活。本文将介绍ReactRouter的使用方法,并提供一些具体的代码示例。安装ReactRouter首先,我们需

See all articles