찾다
웹 프론트엔드JS 튜토리얼Vue에 컨테이너 구성 요소 및 디스플레이 구성 요소를 소개하는 React에 대한 자세한 튜토리얼

이 글은 주로 Vue에 컨테이너 컴포넌트와 디스플레이 컴포넌트를 소개하는 상세한 튜토리얼을 소개하고 있습니다. 이 글에서는 컨테이너 컴포넌트를 사용하는 이유를 아주 자세하게 소개하고 있습니다. 도움이 필요한 친구들이 참고할 수 있습니다.

Redux를 사용하여 React를 개발한 적이 있다면, 컨테이너 컴포넌트(스마트/컨테이너 컴포넌트) 또는 프레젠테이션 컴포넌트(Dumb/프레젠테이션 컴포넌트)에 대해 들어보셨을 것입니다. 이 부서에서 Vue 코드 작성을 배울 수 있나요? 이 기사에서는 이 패턴을 채택해야 하는 이유와 Vue에서 두 구성 요소를 모두 작성하는 방법을 보여줍니다.

컨테이너 구성 요소를 사용하는 이유

주석을 표시하는 구성 요소를 작성하려는 경우 컨테이너 구성 요소에 대해 들어보기 전에 일반적으로 코드는 다음과 같이 작성됩니다.

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

store/index.js

import Vue from &#39;vue&#39;;
import Vuex from &#39;vuex&#39;;

Vue.use(Vuex);

const store = new Vuex.Store({
 state: {
 comments: [],
 },

 mutations: {
 setComments(state, comments) {
  state.comments = comments;
 },
 },

 actions: {
 fetchComments({commit}) {
  setTimeout(() => {
  commit(&#39;setComments&#39;, [
   {
   body: &#39;霸气侧漏&#39;,
   author: &#39;雷叔&#39;,
   id: 1123,
   },
   {
   body: &#39;机智如我&#39;,
   author: &#39;蕾妹&#39;,
   id: 1124,
   },
  ]);
  });
 },
 },
});

export default store;

이렇게 쓰는 게 자연스러운 것 같은데요. ? 아니면 최적화할 수 있는 영역은 어떻습니까?

CommentList.vue와 프로젝트의 Vuex 스토어 간의 결합으로 인해 현재 프로젝트 없이는 재사용이 어렵다는 명백한 문제가 있습니다.

이 문제를 해결할 수 있는 구성 요소를 구성하는 더 좋은 방법이 있습니까? 이제 React 커뮤니티에서 컨테이너 구성 요소의 개념을 이해해야 할 때입니다.

컨테이너 컴포넌트란 무엇인가요?

React.js Conf 2015에서는 컨테이너 컴포넌트를 도입한 고성능 컴포넌트로 앱을 빠르게 만드는 주제가 있었습니다.

컨테이너 구성 요소는 특히 저장소와 통신하고 props를 통해 일반 디스플레이 구성 요소에 데이터를 전달하는 역할을 담당합니다. 디스플레이 구성 요소가 데이터 업데이트를 시작하려는 경우 전달된 콜백 함수를 통해 저장소에도 알립니다. 소품을 통한 컨테이너 구성 요소.

디스플레이 컴포넌트는 더 이상 매장과 직접 연결되지 않고, props 인터페이스를 통해 필요한 데이터와 메소드를 정의하므로 디스플레이 컴포넌트의 재사용성이 높아집니다.

컨테이너 컴포넌트와 디스플레이 컴포넌트의 차이점


디스플레이 컴포넌트컨테이너 컴포넌트Function디스플레이 방법 설명(골격, 스타일)실행 방법 설명(데이터 획득, 상태 업데이트)스토어 직접 사용No 데이터 소스props스토어 상태 듣기데이터 수정props에서 콜백 함수 호출스토어로 작업 전달

来自 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: &#39;CommentListNew&#39;,

 props: {
 comments: {
  type: Array,
  default () {
  return []
  },
  validator (comments) {
  return comments.every(comment =>
   &#39;body&#39; in comment &&
   &#39;author&#39; in comment &&
   &#39;id&#39; 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 &#39;@/components/CommentListNew&#39;

export default {
 name: &#39;CommentListContainer&#39;,

 components: {
 CommentList
 },

 computed: {
 comments () {
  return this.$store.state.comments
 }
 },

 methods: {
 fetchComments () {
  return this.$store.dispatch(&#39;fetchComments&#39;)
 }
 }
}
</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 &#39;@/components/CommentListNew&#39;
import { connector } from &#39;@/store&#39;

export default connector.connect({
 mapStateToProps: {
  comments: (state) => state.comments
 },
 mapActionToProps: {
  fetch: &#39;fetchComments&#39;
 }
})(CommentListNew)
</script>


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

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

问题来了,connector 是什么?

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

import Vue from &#39;vue&#39;;
import Vuex from &#39;vuex&#39;;
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 &#39;vue&#39;;
import App from &#39;./App&#39;;
import store from &#39;./store&#39;;
new Vue({
 el: &#39;#app&#39;,
 components: {App},
 template: &#39;<App/>&#39;,
 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 的声明也会带来少量的工作。

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

相关推荐:

Vue利用canvas实现移动端手写板的方法



위 내용은 Vue에 컨테이너 구성 요소 및 디스플레이 구성 요소를 소개하는 React에 대한 자세한 튜토리얼의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
JavaScript 프레임 워크 : 현대적인 웹 개발 파워JavaScript 프레임 워크 : 현대적인 웹 개발 파워May 02, 2025 am 12:04 AM

JavaScript 프레임 워크의 힘은 개발 단순화, 사용자 경험 및 응용 프로그램 성능을 향상시키는 데 있습니다. 프레임 워크를 선택할 때 : 1. 프로젝트 규모와 복잡성, 2. 팀 경험, 3. 생태계 및 커뮤니티 지원.

JavaScript, C 및 브라우저의 관계JavaScript, C 및 브라우저의 관계May 01, 2025 am 12:06 AM

서론 나는 당신이 이상하다는 것을 알고 있습니다. JavaScript, C 및 Browser는 정확히 무엇을해야합니까? 그들은 관련이없는 것처럼 보이지만 실제로는 현대 웹 개발에서 매우 중요한 역할을합니다. 오늘 우리는이 세 가지 사이의 밀접한 관계에 대해 논의 할 것입니다. 이 기사를 통해 브라우저에서 JavaScript가 어떻게 실행되는지, 브라우저 엔진의 C 역할 및 웹 페이지의 렌더링 및 상호 작용을 유도하기 위해 함께 작동하는 방법을 알게됩니다. 우리는 모두 JavaScript와 브라우저의 관계를 알고 있습니다. JavaScript는 프론트 엔드 개발의 핵심 언어입니다. 브라우저에서 직접 실행되므로 웹 페이지를 생생하고 흥미롭게 만듭니다. 왜 Javascr

Node.js는 TypeScript가있는 스트림입니다Node.js는 TypeScript가있는 스트림입니다Apr 30, 2025 am 08:22 AM

Node.js는 크림 덕분에 효율적인 I/O에서 탁월합니다. 스트림은 메모리 오버로드를 피하고 큰 파일, 네트워크 작업 및 실시간 애플리케이션을위한 메모리 과부하를 피하기 위해 데이터를 점차적으로 처리합니다. 스트림을 TypeScript의 유형 안전과 결합하면 Powe가 생성됩니다

Python vs. JavaScript : 성능 및 효율성 고려 사항Python vs. JavaScript : 성능 및 효율성 고려 사항Apr 30, 2025 am 12:08 AM

파이썬과 자바 스크립트 간의 성능과 효율성의 차이는 주로 다음과 같이 반영됩니다. 1) 해석 된 언어로서, 파이썬은 느리게 실행되지만 개발 효율이 높고 빠른 프로토 타입 개발에 적합합니다. 2) JavaScript는 브라우저의 단일 스레드로 제한되지만 멀티 스레딩 및 비동기 I/O는 Node.js의 성능을 향상시키는 데 사용될 수 있으며 실제 프로젝트에서는 이점이 있습니다.

JavaScript의 기원 : 구현 언어 탐색JavaScript의 기원 : 구현 언어 탐색Apr 29, 2025 am 12:51 AM

JavaScript는 1995 년에 시작하여 Brandon Ike에 의해 만들어졌으며 언어를 C로 실현했습니다. 1.C Language는 JavaScript의 고성능 및 시스템 수준 프로그래밍 기능을 제공합니다. 2. JavaScript의 메모리 관리 및 성능 최적화는 C 언어에 의존합니다. 3. C 언어의 크로스 플랫폼 기능은 자바 스크립트가 다른 운영 체제에서 효율적으로 실행하는 데 도움이됩니다.

무대 뒤에서 : 어떤 언어의 힘이 자바 스크립트입니까?무대 뒤에서 : 어떤 언어의 힘이 자바 스크립트입니까?Apr 28, 2025 am 12:01 AM

JavaScript는 브라우저 및 Node.js 환경에서 실행되며 JavaScript 엔진을 사용하여 코드를 구문 분석하고 실행합니다. 1) 구문 분석 단계에서 초록 구문 트리 (AST)를 생성합니다. 2) 컴파일 단계에서 AST를 바이트 코드 또는 기계 코드로 변환합니다. 3) 실행 단계에서 컴파일 된 코드를 실행하십시오.

파이썬과 자바 스크립트의 미래 : 트렌드와 예측파이썬과 자바 스크립트의 미래 : 트렌드와 예측Apr 27, 2025 am 12:21 AM

Python 및 JavaScript의 미래 추세에는 다음이 포함됩니다. 1. Python은 과학 컴퓨팅 분야에서의 위치를 ​​통합하고 AI, 2. JavaScript는 웹 기술의 개발을 촉진하고, 3. 교차 플랫폼 개발이 핫한 주제가되고 4. 성능 최적화가 중점을 둘 것입니다. 둘 다 해당 분야에서 응용 프로그램 시나리오를 계속 확장하고 성능이 더 많은 혁신을 일으킬 것입니다.

Python vs. JavaScript : 개발 환경 및 도구Python vs. JavaScript : 개발 환경 및 도구Apr 26, 2025 am 12:09 AM

개발 환경에서 Python과 JavaScript의 선택이 모두 중요합니다. 1) Python의 개발 환경에는 Pycharm, Jupyternotebook 및 Anaconda가 포함되어 있으며 데이터 과학 및 빠른 프로토 타이핑에 적합합니다. 2) JavaScript의 개발 환경에는 Node.js, VScode 및 Webpack이 포함되어 있으며 프론트 엔드 및 백엔드 개발에 적합합니다. 프로젝트 요구에 따라 올바른 도구를 선택하면 개발 효율성과 프로젝트 성공률이 향상 될 수 있습니다.

See all articles

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

Video Face Swap

Video Face Swap

완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

뜨거운 도구

SecList

SecList

SecLists는 최고의 보안 테스터의 동반자입니다. 보안 평가 시 자주 사용되는 다양한 유형의 목록을 한 곳에 모아 놓은 것입니다. SecLists는 보안 테스터에게 필요할 수 있는 모든 목록을 편리하게 제공하여 보안 테스트를 더욱 효율적이고 생산적으로 만드는 데 도움이 됩니다. 목록 유형에는 사용자 이름, 비밀번호, URL, 퍼징 페이로드, 민감한 데이터 패턴, 웹 셸 등이 포함됩니다. 테스터는 이 저장소를 새로운 테스트 시스템으로 간단히 가져올 수 있으며 필요한 모든 유형의 목록에 액세스할 수 있습니다.

SublimeText3 영어 버전

SublimeText3 영어 버전

권장 사항: Win 버전, 코드 프롬프트 지원!

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기