如果你使用过 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 |
