React がコンテナ コンポーネントを Vue に導入する方法は何ですか?
今回は、Vueにコンテナコンポーネントを導入するReactの方法と、Vueにコンテナコンポーネントを導入するReactの注意事項を紹介します。
React の開発に Redux を使用したことがある方は、コンテナ コンポーネント (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, }, ]); }); }, }, });
exportdefaultstore;
このように書くと自然に思えますが、問題や最適化できる領域はありますか?
CommentList.vue とプロジェクトの Vuex ストアとの間には明らかな問題があり、現在のプロジェクトなしでそれを再利用するのは困難です。
この問題を解決できる、コンポーネントを整理するより良い方法はありますか? React コミュニティにおけるコンテナ コンポーネントの概念を理解する時期が来ました。
コンテナ コンポーネントとは何ですか?
React.js Conf 2015 では、コンテナ コンポーネントを紹介する高パフォーマンス コンポーネントでアプリを高速化するというトピックがありました。
コンテナコンポーネントはストアとの通信を特に担当し、表示コンポーネントがデータの更新を開始したい場合は、渡されたコールバック関数を通じてストアにデータを渡します。コンテナコンポーネントの小道具。
表示コンポーネントはストアに直接結合されなくなり、必要なデータとメソッドが props インターフェースを通じて定義されるため、表示コンポーネントの再利用性が高くなります。
コンテナコンポーネントとディスプレイコンポーネントの違い
表示コンポーネント |
コンテナコンポーネント | |
---|---|---|
機能 | 表示方法の説明(スケルトン、スタイル) | 実行方法の説明(データ取得、ステータス更新) |
ストアを直接使用 | いいえ | はい |
データソース | 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: '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中文网其它相关文章!
推荐阅读:
以上がReact がコンテナ コンポーネントを Vue に導入する方法は何ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック











win10で一部のゲームをプレイすると、画面がフリーズしたり画面がぼやけるなどの不具合が多くのユーザーに発生しますが、現時点ではダイレクトプレイ機能をオンにすることで問題を解決でき、機能の操作方法も非常に簡単です。 win10 の古いコンポーネントである Directplay をインストールする方法 1. 検索ボックスに「コントロール パネル」と入力して開きます 2. 表示方法として大きなアイコンを選択します 3. 「プログラムと機能」を見つけます 4. 左側をクリックして有効にするか、 Win 機能をオフにする 5. ここで古いバージョンを選択します チェックボックスをオンにするだけです

React と RabbitMQ を使用して信頼性の高いメッセージング アプリケーションを構築する方法 はじめに: 最新のアプリケーションは、リアルタイム更新やデータ同期などの機能を実現するために、信頼性の高いメッセージングをサポートする必要があります。 React はユーザー インターフェイスを構築するための人気のある JavaScript ライブラリであり、RabbitMQ は信頼性の高いメッセージング ミドルウェアです。この記事では、React と RabbitMQ を組み合わせて信頼性の高いメッセージング アプリケーションを構築する方法を紹介し、具体的なコード例を示します。 RabbitMQ の概要:

ReactRouter ユーザーガイド: フロントエンドルーティング制御の実装方法 シングルページアプリケーションの人気に伴い、フロントエンドルーティングは無視できない重要な部分になりました。 React エコシステムで最も人気のあるルーティング ライブラリとして、ReactRouter は豊富な機能と使いやすい API を提供し、フロントエンド ルーティングの実装を非常にシンプルかつ柔軟にします。この記事では、ReactRouter の使用方法と具体的なコード例を紹介します。 ReactRouter を最初にインストールするには、次のものが必要です

PHP、Vue、React: 最適なフロントエンド フレームワークを選択するには?インターネット技術の継続的な発展に伴い、フロントエンド フレームワークは Web 開発において重要な役割を果たしています。 PHP、Vue、React は 3 つの代表的なフロントエンド フレームワークであり、それぞれに独自の特徴と利点があります。使用するフロントエンド フレームワークを選択するとき、開発者はプロジェクトのニーズ、チームのスキル、個人の好みに基づいて情報に基づいた決定を下す必要があります。この記事では、PHP、Vue、React の 3 つのフロントエンド フレームワークの特徴と用途を比較します。

Angular フレームワークのコンポーネントのデフォルトの表示動作は、ブロックレベルの要素ではありません。この設計の選択により、コンポーネント スタイルのカプセル化が促進され、開発者が各コンポーネントの表示方法を意識的に定義することが促進されます。 CSS プロパティの表示を明示的に設定することで、Angular コンポーネントの表示を完全に制御して、目的のレイアウトと応答性を実現できます。

Win10 の古いバージョンのコンポーネントは、デフォルトで閉じられていることが多いため、ユーザー自身が設定で有効にする必要があります。まず、設定を入力する必要があります。操作は非常に簡単です。以下の手順に従ってください。Win10 の古いバージョンはどこにありますか?バージョン コンポーネント? 開く 1. [スタート] をクリックし、[Win システム] をクリックします 2. クリックしてコントロール パネルに入ります 3. 次に、下のプログラムをクリックします 4. [Win 機能を有効または無効にする] をクリックします 5. ここで必要なものを選択できます開く

Java フレームワークと React フレームワークの統合: 手順: バックエンド Java フレームワークをセットアップします。プロジェクト構造を作成します。ビルドツールを設定します。 React アプリケーションを作成します。 REST API エンドポイントを作成します。通信メカニズムを構成します。実際のケース (SpringBoot+React): Java コード: RESTfulAPI コントローラーを定義します。 React コード: API によって返されたデータを取得して表示します。

1G 独立グラフィックスを備えた i34150 ではどのようなゲームをプレイできますか? LoL などの小さなゲームもプレイできますか? GTX750 および GTX750TI は、グラフィックス カードの選択肢として非常に適しています。小規模なゲームをプレイするだけの場合、またはゲームをプレイしない場合は、i34150 統合グラフィックス カードを使用することをお勧めします。一般に、グラフィックス カードとプロセッサーの価格差はそれほど大きくないため、合理的な組み合わせを選択することが重要です。 2G のビデオ メモリが必要な場合は、GTX750TI を選択することをお勧めします。1G のビデオ メモリのみが必要な場合は、GTX750 を選択してください。 GTX750TI は、オーバークロック機能を備えた GTX750 の強化版と見なされます。どのグラフィックス カードを i34150 と組み合わせることができるかはニーズによって異なります。スタンドアロン ゲームをプレイする予定がある場合は、グラフィックス カードの変更を検討することをお勧めします。選んでいいですよ
