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

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

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

为什么要使用容器组件?

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

components/CommentList.vue

 
  • {{comment.body}}—{{comment.author}}
export default { name: 'CommentList', computed: { comments () { return this.$store.state.comments } }, mounted () { this.$store.dispatch('fetchComments') }}

登录后复制

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 的主题介绍了容器组件。

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

容器组件专门负责和 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。

 
  • {{comment.body}}—{{comment.author}}
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() }}

登录后复制

containers/CommentListContainer.vue

容器组件的职责

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

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

 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') } }}

登录后复制

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

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

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

代码比较繁琐

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

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

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

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


登录后复制

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

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

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

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

使用 @xunlei/vuex-connector

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

有以下几个特点:

代码非常简洁

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

comonents/ConnectCommentListContainer.vue

import CommentListNew from '@/components/CommentListNew'import { connector } from '@/store'export default connector.connect({ mapStateToProps: {  comments: (state) => state.comments }, mapActionToProps: {  fetch: 'fetchComments' }})(CommentListNew)

登录后复制

通过 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: '', 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 。

@Componentexport default class Hello extends Vue { @Prop info: IHelloInfo; // 这里可以用你自定义的 interface}

登录后复制

可测试性

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

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

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

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

学习和开发成本

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

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

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

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

相信看了本文案例你已经掌握了方法,更多精彩请关注【创想鸟】其它相关文章!

推荐阅读:

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

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

以上就是React给Vue引入容器组件有哪些方法的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2761954.html

(0)
上一篇 2025年3月8日 09:42:45
下一篇 2025年3月8日 09:42:55

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • Vue表单类父子组件数据传递数据方法总结

    这次给大家带来Vue表单类父子组件数据传递数据方法总结,Vue表单类父子组件数据传递数据的注意事项有哪些,下面就是实战案例,一起来看一下。 使用Vue.js进行项目开发,那必然会使用基于组件的开发方式,这种方式的确给开发和维护带来的一定的便…

    编程技术 2025年3月8日
    200
  • react router4+redux控制路由权限步骤详解

    这次给大家带来react router4+redux控制路由权限步骤详解,react router4+redux控制路由权限的注意事项有哪些,下面就是实战案例,一起来看一下。 总体概述 一个完善的路由系统应该是这样子的,当链接到的组件是需要…

    编程技术 2025年3月8日
    200
  • Vue中slot插槽分发父组件内容实现复用方便步骤详解

    这次给大家带来Vue中slot插槽分发父组件内容实现复用方便步骤详解,Vue中slot插槽分发父组件内容实现复用方便的注意事项有哪些,下面就是实战案例,一起来看一下。 写在前面 之前写过一篇关于vue实现dialog会话框组件的文章http…

    2025年3月8日
    200
  • Vue波纹按钮组件使用详解

    这次给大家带来Vue波纹按钮组件使用详解,Vue波纹按钮组件使用的注意事项有哪些,下面就是实战案例,一起来看一下。 先说一下用法: 默认按钮默认按钮定义速度和初始的波浪透明度 登录后复制 原理: 这里用的是canvas + requestA…

    编程技术 2025年3月8日
    200
  • 操作JS中DOM节点有哪些方法

    这次给大家带来操作JS中DOM节点有哪些方法,操作JS中DOM节点的注意事项有哪些,下面就是实战案例,一起来看一下。 DOM操作在JS中可以说是非常常见了吧,很多网页的小功能的实现,比如一些元素的增删操作等都可以用JS来实现。那么在DOM中…

    2025年3月8日
    200
  • React native ListView在移动端中添加顶部下拉刷新与底部点击刷新案例详解

    这次给大家带来react native listview在移动端中添加顶部下拉刷新与底部点击刷新案例详解,react native listview在移动端中添加顶部下拉刷新与底部点击刷新的注意事项有哪些,下面就是实战案例,一起来看一下。 …

    2025年3月8日
    200
  • React Native日期时间选择组件实例详解

    这次给大家带来React Native日期时间选择组件实例详解,使用React Native日期时间选择组件的注意事项有哪些,下面就是实战案例,一起来看一下。 React Native日期时间选择组件:react-native-datepi…

    2025年3月8日
    200
  • react创建单例组件步骤详解

    这次给大家带来react创建单例组件步骤详解,react创建单例组件的注意事项有哪些,下面就是实战案例,一起来看一下。 需求背景 最近有个需求,需要在项目中添加一个消息通知弹窗,告知用户一些信息。 用户看过消息后,就不再弹窗了。 问题 很明…

    编程技术 2025年3月8日
    200
  • js中对小数取整的方法有哪些?(图文教程)

    下面是我给大家整理的在js中对小数取整的方法有哪些?,有兴趣的同学可以去看看。 1.丢弃小数部分,保留整数部分  js:parseInt(7/2) 登录后复制 2.向上取整,有小数就整数部分加1  js: Math.ceil(7/2) 登录…

    编程技术 2025年3月8日
    200
  • 详细解答react

    react算是目前最火的js mvc框架了,写一个react系列的博客,顺便回忆一下react的基础知识,新入门前端的小白,可以持续关注,我会从零开始教大家用react开发一个完整的项目,也会涉及到webpack,node等前端知识,每天会…

    编程技术 2025年3月8日
    200

发表回复

登录后才能评论