我们提请您注意Scott Domes的文章翻译,该文章已发布在blog.bitsrc.io上。 在kat上找出为什么组件应该尽可能小,以及唯一责任原则如何影响应用程序的质量。
奥斯汀 ·柯克(
Unstinsplash)的照片
React组件系统(和类似的库)的优点是您的UI分为易于阅读和可重用的小部分。
这些组件非常紧凑(100-200行),这使其他开发人员可以轻松理解和修改它们。
尽管通常会尽量缩短组件,但没有明确,严格的长度限制。 如果您决定将您的应用程序放入一个由3000行组成的可怕的巨大组件中,React不会介意。
...但这是不值得的。 您的大多数组件很可能已经太庞大了-或说,它们执行了太多的功能。
在本文中,我将证明大多数组件(即使具有通常的200行长度)也应更严格地定位。 他们应该只执行一项功能,并执行良好。 这就是Eddie Osmani
在这里所说的很棒。
提示 :在JS中工作时,请
使用Bit来组织,组装和重用作为lego部件的组件。 Bit是用于此业务的极其有效的工具,它将帮助您和您的团队节省时间并加快组装速度。 试一试。
让我们演示一下在创建组件时如何
出错 。
我们的应用
想象一下,我们有一个针对博客的标准应用程序。 这是主屏幕上的内容:
class Main extends React.Component { render() { return ( <div> <header> // Header JSX </header> <aside id="header"> // Sidebar JSX </aside> <div id="post-container"> {this.state.posts.map(post => { return ( <div className="post"> // Post JSX </div> ); })} </div> </div> ); } }
(此示例与许多后续示例一样,应视为伪代码。)它显示顶部面板,侧边栏和帖子列表。 一切都很简单。
由于我们还需要下载帖子,因此我们可以在安装组件时执行以下操作:
class Main extends React.Component { state = { posts: [] }; componentDidMount() { this.loadPosts(); } loadPosts() {
我们也有一些逻辑来调用侧边栏。 如果用户单击上部面板中的按钮,则该侧将退出。 您可以从顶部和侧面板本身将其关闭。
class Main extends React.Component { state = { posts: [], isSidebarOpen: false }; componentDidMount() { this.loadPosts(); } loadPosts() {
我们的组件变得有些复杂,但仍然易于阅读。
可以说,它的所有部分都有一个目的:显示应用程序的主页。 因此,我们遵循唯一责任原则。
唯一责任原则规定,一个组件应仅履行一项功能。 如果我们重新定义来自
wikipedia.org的定义,那么事实证明每个组件仅应负责功能[应用程序]的一部分。
我们的主要组件满足此要求。 怎么了
这是原则的另一种表述:
任何[组件]应该只有一个改变的理由 。
这个定义来自Robert Martin的
书,Rapid Software Development。 原则,示例,实践” ,这一点非常重要。
通过关注
更改组件的
一个原因 ,我们可以创建更好的应用程序,而且这些应用程序将易于配置。
为了清楚起见,让我们使组件复杂化。
并发症
假设在实现Main组件一个月后,我们团队为开发人员分配了一项新功能。 现在,用户将能够隐藏帖子(例如,如果帖子包含不适当的内容)。
这并不难!
class Main extends React.Component { state = { posts: [], isSidebarOpen: false, postsToHide: [] };
我们的同事很容易处理这个问题。 她只添加了一种新方法和一种新属性。 那些浏览简短变更清单的人都没有异议。
几周后,又宣布了另一个功能-改进了移动版本的侧边栏。 开发人员决定创建几个仅在移动设备上运行的JSX组件,而不是弄乱CSS。
class Main extends React.Component { state = { posts: [], isSidebarOpen: false, postsToHide: [], isMobileSidebarOpen: false };
另一个小变化。 几个新的命名良好的方法和一个新的属性。
这里我们有一个问题。
Main
仍然仅执行一个功能(渲染主屏幕),但是您将看到我们现在正在处理的所有这些方法:
class Main extends React.Component { state = { posts: [], isSidebarOpen: false, postsToHide: [], isMobileSidebarOpen: false }; componentDidMount() { this.loadPosts(); } loadPosts() {
我们的组件变得又大又笨重,很难理解。 随着功能的扩展,情况只会恶化。
怎么了?
唯一原因
让我们回到唯一责任原则的定义:
任何组件都应该只有一个改变的理由 。
以前,我们更改了帖子的显示方式,因此我们不得不更改主要组件。 接下来,我们更改了侧边栏的打开方式-再次更改了Main组件。
该组件具有许多无关的更改原因。
这意味着它执行了太多功能 。
换句话说,如果您可以显着更改组件的一部分,而不会导致其另一部分发生更改,则您的组件负有太多责任。
更有效的分离
解决方案很简单:您需要将Main组件分为几个部分。 怎么做?
让我们重新开始。 主屏幕的呈现仍然是Main组件的责任,但我们仅将其缩小以显示相关组件:
class Main extends React.Component { render() { return ( <Layout> <PostList /> </Layout> ); } }
太好了
如果我们突然更改了主屏幕的布局(例如,添加了其他部分),那么Main也会更改。 在其他情况下,我们没有理由碰他。 太好了
让我们继续
Layout
:
class Layout extends React.Component { render() { return ( <SidebarDisplay> {(isSidebarOpen, toggleSidebar) => ( <div> <Header openSidebar={toggleSidebar} /> <Sidebar isOpen={isSidebarOpen} close={toggleSidebar} /> </div> )} </SidebarDisplay> ); } }
这有点复杂。
Layout
负责渲染布局组件(侧面板/顶面板)。 但是,我们不会屈服于诱惑,而让
Layout
负责确定侧边栏是否打开。
我们将此功能分配给
SidebarDisplay
组件,该组件将必要的方法或状态传递给
Header
和
Sidebar
组件。
(上面的示例是React中“ 通过子代渲染道具”模式的示例。如果您不熟悉它,不用担心。重要的是,有一个单独的组件来控制侧边栏的打开/关闭状态。)然后,如果侧边栏仅负责在右侧渲染侧边栏,则它本身可以非常简单。
class Sidebar extends React.Component { isMobile() {
再次,我们抵制了将用于计算机/移动设备的JSX直接插入此组件的诱惑,因为在这种情况下,它将有两个更改原因。
让我们看一下另一个组件:
class PostList extends React.Component { state = { postsToHide: [] } filterPosts(posts) {
仅当我们更改帖子列表的
PostList
方式时,
PostList
才会更改。 似乎很明显,对不对? 这正是我们所需要的。
仅当我们更改帖子的加载方式时,
PostLoader
才会更改。 最后,仅当我们更改帖子的呈现方式时,
Post
才会更改。
结论
所有这些组件都很微小,仅执行一项小功能。 这些更改的原因很容易识别,并且组件本身已经过测试和纠正。
现在,我们的应用程序更易于修改-重新排列组件,添加新功能并扩展现有功能。 您只需要查看组件文件即可确定其用途。
我们知道我们的组成部分会随着时间的推移而变化和增长,但是应用此通用规则将帮助您避免技术负担并提高团队速度。 如何分配组件取决于您,但是请记住-
更改组件必须只有一个原因 。
感谢您的关注,并期待您的评论!