Summary - typical reasons for using components:(摘要-使用组件的典型原因:)
- Maintainability.(可维护性。)
- Rendering performance via component boundaries.(通过组件边界的渲染性能。)
- Loading performance via chunking.(通过分块加载性能。)
If you find that using fewer components improves maintainability then that's fine.(如果您发现使用更少的组件可以提高可维护性,那很好。)
It may well be the correct design for your application.(这很可能是适合您的应用程序的正确设计。)
Verbose version below.(详细版本如下。)
The primary reason for using components is to improve maintainability.(使用组件的主要原因是为了提高可维护性。)
Components that are reused in many places such as a select-box are obviously easier to maintain than repeating the same code over and over.(在很多地方重用的组件(例如选择框)显然比一遍又一遍地重复相同的代码更容易维护。)
However, it is worth considering why that is.(但是,这是值得考虑的。) It's not just that duplication makes it more difficult to make a change to all of the select-boxes.(不仅仅是因为重复使得更改所有选择框变得更加困难。) The other key benefit of using a component is that the extra level of abstraction can reduce mental overhead.(使用组件的另一个主要好处是额外的抽象级别可以减少思想上的开销。)
Let's say someone trying to maintain the code sees something like this (pseudo-code):(假设有人试图维护代码,看到的东西是这样的(伪代码):)
<select-box :some-prop="blah">
<select-box-option v-for="something" />
</select-box>
Immediately it's clear that this is a select-box
.(马上很明显,这是一个select-box
。)
All the gory implementation details of the select-box
are hidden away and we don't need to worry about them.(select-box
所有gory实现细节都被隐藏了,我们不必担心它们。) By looking at the props, child components and events we can quickly deduce what data goes back-and-forth between the parent component and the select-box
.(通过查看道具,子组件和事件,我们可以快速推断出哪些数据在父组件和select-box
之间来回select-box
。) This is just separation of concerns .(这只是关注点分离 。)
This benefit also applies to components that aren't reused.(此好处也适用于未重用的组件。)
Let's take the sidebar example.(让我们以边栏示例为例。) We might see this in the template for our main component:(我们可能会在主要组件的模板中看到以下内容:)
<nav-sidebar @navigate="onNavigate" />
The component's name allows us to quickly identify it as the sidebar.(组件的名称使我们可以快速将其标识为侧边栏。)
If our current task doesn't involve the sidebar then we can just skip over that bit of the template.(如果我们当前的任务不涉及边栏,那么我们可以跳过模板的那一部分。) As the code has been moved off to a different file we have no difficulty establishing which bits of the code are part of the sidebar and which bits aren't.(由于代码已移至其他文件,因此我们不难确定代码的哪些位是侧边栏的一部分,哪些位不是。)
In this example the nav-sidebar
doesn't have any props and only has a single event.(在这个例子中, nav-sidebar
没有任何道具,只有一个事件。)
From that we can start to draw some conclusions about how these components interact.(由此,我们可以开始得出有关这些组件如何相互作用的一些结论。) It would seem that the nav-sidebar
doesn't need anything passed from the main component, it could quite happily live stand-alone.(nav-sidebar
似乎不需要从主要组件传递的任何内容,它可以很高兴地独立运行。) If we need to debug a problem with data flowing the other way we'd almost certainly start with onNavigate
.(如果我们需要用另一种方式调试数据流问题,则几乎可以肯定从onNavigate
开始。)
We couldn't start making deductions like these anything like as quickly if everything was mangled together into one, big component.(如果一切都被整合为一个大的组成部分,我们就不可能像这样迅速地做出类似的推论。)
Of course it could be that our deductions are wrong.(当然,这可能是我们的推论是错误的。)
It could be that the nav-sidebar
does some horrible things involving $parent
to grab data from its parent component.(nav-sidebar
做了一些可怕的事情,涉及到$parent
来从其父组件中获取数据。) However, that just illustrates why using such techniques is considered bad practice.(但是,这仅说明了为什么使用这种技术被认为是不好的做法。) Maintainable code should allow developers to jump to reasonable conclusions based on the abstractions that appear to be in place.(可维护的代码应允许开发人员根据似乎已到位的抽象,跳到合理的结论。)
But it is possible to go too far the other way.(但是有可能走得太远。)
A good abstraction allows you to free up some mental capacity by hiding details behind a label.(好的抽象可以让您通过将细节隐藏在标签后面来释放一些思维能力。)
A poor abstraction adds mental overhead by hiding the code you want to see behind some indirection.(较差的抽象通过将您想看到的代码隐藏在某种间接后面而增加了精神上的开销。) Add to that the difficulty of naming things and the burden of extra glue code and you may well be better off just ditching the extra layers and keeping everything inline.(再加上命名的难度和额外的粘合代码的负担,最好放弃一些额外的层并使所有内容保持内联。)
The other thing that can go wrong is splitting components up in the wrong way.(可能出错的另一件事是以错误的方式拆分组件。)
Separating concerns requires clean partitions of those concerns.(分离关注点需要对这些关注点进行干净的划分。) Chop things up slightly differently and you end up with a single concern being spread across multiple components and the resulting mess is typically worse than if you hadn't bothered splitting things up at all.(将事情切碎的方式略有不同,最终会导致单个问题分散在多个组件中,并且所产生的混乱情况通常比不进行拆分的情况更糟。)
Vue allows you to split up your JavaScript code in a number of ways, components being just one.(Vue允许您以多种方式拆分JavaScript代码,而组件只是其中一种。)
Separate .js
files, plugins, filters, Vuex, mixins, etc.. There are several options available to you.(单独的.js
文件,插件,过滤器,Vuex,mixins等。您可以使用几个选项。)
Templates, on the other hand, can only really be split up by using components.(另一方面,只能使用组件来真正拆分模板。)
If you want to break a huge template down into more manageable chunks then components are really the only way to go.(如果您想将一个巨大的模板分解为更多可管理的块,那么组件确实是唯一的选择。)
This brings us to another key reason for using components.(这使我们想到了使用组件的另一个关键原因。)
A template is compiled down into a render
function.(模板被编译成render
函数。)
When that render
function is run it registers reactive dependencies, just like a computed property.(运行该render
函数时,它会注册反应性依赖项,就像计算的属性一样。) If any of those dependencies changes it will trigger a re-render.(如果这些依赖项中的任何一项发生更改,它将触发重新渲染。) That runs the whole render
function again.(那将再次运行整个render
功能。) Even if that doesn't result in any changes to the DOM it will require the generation of all the relevant VNodes and the diffing algorithm will need to check all of them.(即使这不会导致DOM发生任何变化,也将需要生成所有相关的VNode,并且差异算法将需要检查所有这些VNode。)
Component boundaries are also rendering boundaries.(组件边界也是渲染边界。)
Each component makes its own decision about whether or not to render based on whether its dependencies have changed.(每个组件都根据其依赖项是否已更改来决定是否渲染。)
So, taking the nav-sidebar
example, let's say something changes in the nav-sidebar
so that it needs a rendering update.(因此,服用nav-sidebar
例子,比方说在一些变化nav-sidebar
,以便它需要一个描绘更新。)
If the nav-sidebar
is a separate component then it just needs to run the template/ render
function for that component.(如果nav-sidebar
是一个单独的组件,则只需运行该组件的模板/ render
功能。) If instead we bundle all the nav-sidebar
code into the main template then we'll have to re-render everything.(相反,如果我们将所有nav-sidebar
代码捆绑到主模板中,那么我们将不得不重新呈现所有内容。)
Vue also has support for lazily loaded components as a way to reduce the initial load time of the page.(Vue还支持延迟加载的组件,以减少页面的初始加载时间。)
The idea is that many applications have large sections, such as admin interfaces, that aren't relevant to most users.(这个想法是,许多应用程序都具有与大多数用户无关的较大部分,例如管理界面。) Rather than incurring the overhead of downloading all of those components you can split the components into chunks and download the chunks when they're needed.(无需承担下载所有这些组件的开销,您可以将这些组件拆分为多个块,并在需要时下载这些块。) This is usually implemented via the Vue router configuration.(这通常是通过Vue路由器配置实现的。)
Chunking aside, the typical way to use the router is to have separate components for the different pages.(除了块之外,使用路由器的典型方法是为不同的页面使用单独的组件。)
While in theory it is possible to use the same component for all routes that is unlikely to lead to something more maintainable.(从理论上讲,可以对所有路线使用相同的组件,这不太可能导致某些事情更容易维护。) I would add that the definition of 'page' is a little fuzzy here but in most applications it's clear what constitutes a different page, resulting in a different component.(我要补充一点,这里的“页面”的定义有点模糊,但是在大多数应用程序中,很清楚什么构成了不同的页面,从而导致了不同的组件。)
No tome on creating code monoliths would be complete without some mention of testing.(如果不提及测试,就无法完成创建代码整体的工作。)
Unit testing should be thought of as a form of reuse and a particularly extreme form at that.(单元测试应该被认为是一种重用形式,并且在这方面是一种极端的形式。) Tests have an unrelenting knack for exposing the mess of spaghetti that hides behind what you thought was a nice, clean design.(测试对于揭露隐藏在您认为不错,干净的设计背后的意大利面一团糟有着无情的诀窍。) I'm not going to pontificate on testing but suffice it to say that you won't be able to write unit tests unless you split things into suitable units.(我不会夸大测试,但是足以说明您将不能将单元测试拆分为合适的单元,否则就无法编写单元测试。)
Another key feature of a component is that it has its own set of properties.(组件的另一个关键特性是它具有自己的一组属性。)
Its own data
and its own computed properties.(它自己的data
和自己的计算属性。) This sounds obvious but it gains significance when you consider looping via v-for
.(这听起来很明显,但是当您考虑通过v-for
循环时,它就变得很重要。)
<div v-for="item in items">...</div>
The example above uses inline elements instead of components.(上面的示例使用内联元素而不是组件。)
Any state can only live on the parent.(任何状态都只能生活在父项上。) That state needs to be held for each loop item, so we may end up with multiple arrays holding different aspects of the state.(该状态需要为每个循环项保留,因此我们可能最终会得到多个保存状态不同方面的数组。) Computed properties are similarly difficult to implement when working with loops.(处理循环时,计算属性同样难以实现。) We typically end up using methods instead:(我们通常最终使用方法代替:)
<div v-for="item in items" :class="getClassesFor(item)">...</div>
Now consider the component version:(现在考虑组件版本:)
<my-component v-for="item in items" :i