可靠React组件设计的7个准则之组合和复用

时间: 2019-07-12阅读: 27标签: 组件

此篇文章对编写可重用和可维护的React组件非常有帮助。但因为篇幅实在太长,我对文章进行了分割,本篇文章重点阐述 组合和复用。因水平有限,文中部分翻译可能不够准确。 更多文章可戳: https://github.com/YvetteLau/ 


组合

一个组合式组件是由更小的特定组件组合而成的。

组合(composition)是一种通过将各组件联合在一起以创建更大组件的方式。组合是 React 的核心。

幸运的是,组合易于理解。把一组小的片段,联合起来,创建一个更大个儿。

让我们来看一个常见的前端应用组合模式。应用由头部的 header、底部的 footer、左侧的 sidebar,还有中部的有效内容联合而成:


<div id="root"></div>
function Application({ children }) {
    return (
        <div className="application box">
            <Label>Application</Label>
            {children}
        </div>
    );
}

function Header() {
    return (
        <div className="header box">
            <Label>Header</Label>
        </div>
    )
}

function Footer() {
    return (
        <div className="header box">
            <Label>Footer</Label>
        </div>
    )
}

function Sidebar({ children }) {
    return (
        <div className="sidebar box">
            <Label>Sidebar</Label>
            {children}
        </div>
    );
}

function Content({ children }) {
    return (
        <div className="content box">
            <Label>Content</Label>
            {children}
        </div>
    )
}

function Menu() {
    return (
        <div className="menu box">
            <Label>Menu</Label>
            <div className="description">
                <div className="text shorter" />
                <div className="text" />
                <div className="text shorter" />
                <div className="text shorter" />
            </div>
        </div>
    );
}

function Article() {
    return (
        <div className="article box">
            <Label>Article</Label>
            <div className="description">
                <div className="text shorter" /> <div className="text longer" />
                <div className="text shorter" /> <div className="text" />
                <div className="text shorter" /> <div className="text" />
                <div className="text" /> <div className="text shorter" />
                <div className="text shorter" /> <div className="text" />
                <div className="text" /> <div className="text shorter" />
                <div className="text shorter" /> <div className="text longer" />
                <div className="text shorter" /> <div className="longer" />
                <div className="text shorter" /> <div className="text" />
                <div className="text" /> <div className="text shorter" />
                <div className="text shorter" /> <div className="text" />
            </div>
        </div>
    );
}

function Label({ children }) {
    return <div className="label">&lt;{children}&gt;</div>
}

const app = (
    <Application>
        <Header />
        <Sidebar>
            <Menu />
        </Sidebar>
        <Content>
            <Article />
        </Content>
        <Footer />
    </Application>
);

ReactDOM.render(app, document.getElementById('root')); 

应用程序演示了组合如何构建应用程序。这种组织这样组织代码即富于表现力又便于理解。

React 组件的组合是自然而然的。这个库使用了一个声明范式,从而不会抑制组合式的表现力。

<Application> 由 <Header> 、 <Sidebar> <Content> 和 <Footer> 组成. <Sidebar> 有一个 <Menu> 组件, <Content>有一个 <Article> 组件.

那么组合与单一责任以及封装有什么联系呢?让我们一起看看:

单一责任原则描述了如何将需求拆分为组件,封装描述了如何组织这些组件,组合描述了如何将整个系统粘合在一起。


组合的好处

单一责任

组合的一个重要方面在于能够从特定的小组件组成复杂组件的能力。这种分而治之的方式帮助了被组合而成的复杂组件也能符合 SRP 原则。

回顾之前的代码片段,<Application> 负责渲染 header 、footer 、sidebar 和主体区域。

将此职责分为四个子职责是有意义的,每个子职责由专门的组件实现,分别是<header> 、<sidebar> 、<content> 和 <footer>。随后,这些组件被粘合在 <Application> 。

现在来看看组合的好处:通过子组件分别实现单一职责的方式,使 <Application> 组件也符合单一责任原则。

可重用

组合有可重用的有点,使用组合的组件可以重用公共逻辑,

例如,组件 <Composed1> 和 <Composed2> 有一些公共代码:

const instance1 = (
    <Composed1>
    /* Specific to Composed1 code... */
    /* Common code... */
    </Composed1>
);
const instance2 = (
    <Composed2>
    /* Common code... */
    /* Specific to Composed2 code... */
    </Composed2>
);

代码复制是一个不好的实践(例如更改 Composed1 的代码时,也需要去更改Composed2 中的代码),那么如何使组件重用公共代码?

首先,将共同代码封装到一个新组件中,如 <Common> 中,然后

首先,在新组件中封装公共代码。其次,<Composed1> 和 <Composed2> 应该使用组合的方式来包含 <Common>组件,以避免代码重复,如下:

const instance1 = (
    <Composed1>
        <Piece1 />
        <Common />
    </Composed1>
);
const instance2 = (
    <Composed2>
        <Common />
        <Piece2 />
    </Composed2>
);

可重用的组件符合不重复自己(Don't repeat yourself)的原则。这种做法可以节省你的精力和时间,并且在后期,有利于代码维护。

灵活

在 react 中,一个组合式的组件通过给子组件传递 props 的方式,来控制其子组件。这就带来了灵活性的好处。

例如,有一个组件,它需要根据用户的设备显示信息,使用组合可以灵活地实现这个需求:

function ByDevice({ children: { mobile, other } }) {
    return Utils.isMobile() ? mobile : other;
}

<ByDevice>{{
    mobile: <div>Mobile detected!</div>,
    other: <div>Not a mobile device</div>
}}</ByDevice>

<ByDevice> 组合组件,对于移动设备,显示: Mobile detected!; 对于非移动设备,显示 Not a mobile device"。

高效

用户界面可组合的层次结构,因此,组件的组合是一种构建用户界面的有效的方式。

注:DRY 原则理论上来说是没有问题的,但在实际应用是切忌死搬教条。它只能起指导作用,没有量化标准,否则的话理论上一个程序每一行代码都只能出现一次才行,这是非常荒谬的,其它的原则也是一样,起到的也只是指导性的作用。


复用

可重用的组件,一次编写多次使用。

想象一下,如果软件开发总是重复造轮子。那么当你编写代码时,不能使用任何已有库或工具。甚至在同一个应用中你都不能使用已经编写过的代码。在这种环境中,是否有可能在合理的时间内编写出一个应用呢?绝无可能。

此时应该到认识重用的重要性,使用已有的库或代码,而不是重复造轮子。

应用内的复用

根据“不要重复自己”(DRY)原则,每一条知识都必须在系统中具有单一,明确,权威的表示。这个原则建议避免重复。

代码重复增加了复杂性和维护工作,但没有增加显著的价值。逻辑更新迫使您修改应用程序中的所有重复代码。

重复问题可以用可复用组件来解决。一次编写,多次使用。

但是,复用并非毫无成本。只有一个组件符合单一责任原则并且具有合理的封装时,它是可复用的。

符合单一职责原则是必须的:

复用一个组件实际上就意味着复用其职责

只有一个职责的组件是最容易复用的。

但是,当一个组件错误地具有多个职责时,它的复用会增加大量的开销。你只想复用一个职责实现,但也会得到不必要的职责实现。比如,你只是想要一个香蕉,但是在你得到一个香蕉的同时,不得不被迫接受所有的丛林。

合理封装的组件。隐藏了内部实现,并且有明确的 props ,使得组件可以使用与多种需要复用的场合。


复用第三方库

某个工作日,你刚刚收到了为应用增加新特性的任务,在撩起袖子狂敲代码之前,先稍等几分钟。

你要做的工作在很大概率上已经被解决了。由于 React 非常流行以及其非常棒的开源社区,先搜索一下是否有已存在的解决方案是明智之举。

查看 brillout/awesome-react-components ,它有一个可复用的组件列表。

优秀的第三方库有结构性的影响,并且会推广最佳实践。以我的经验而言,最有影响的当属 react-router 和 redux。

react-router 使用了声明式的路由来构建一个单页应用。使用 <Route> 将 URL 和组件关联起来。当用户访问匹配的 URL时,路由将渲染相应的组件。

redux 和 react-redux 引入了单向和可预测的应用状态管理。可以将异步的和非纯的代码(例如 HTTP 请求)从组件中提取出来,从而符合单一职责原则并创建出 纯(pure)组件 或 几乎纯(almost-pure)的组件。

这里是一份检查清单可以确定第三方库是否值得使用:
  • 文档:检查库是否具备有意义的 README.md 文件和详细的文档
  • 测试过的:可信赖库的一个显著特征就是有高的测试覆盖率
  • 维护:看看库作者创建新特性、修改bug及日常维护的频率
翻译:刘小夕
原文链接:https://dmitripavlutin.com/


链接: http://www.fly63.com/article/detial/4654

Vue父子组件传值(复杂数据类型的值)

vue 父子组件传值是很常见的,多数情况下都是父传递给子的值是基础数据类型,如string,number,boolean,当父组件值被修改时,子组件能够实时的作出改变。如果父子传值的类型是复杂数据类型(object,array)这种时

使用Typescript装饰器来劫持React组件

装饰器是一种特殊类型的声明,它能够被附加到类声明,方法, 访问符,属性或参数上。 装饰器使用 @expression这种形式,expression求值后必须为一个函数,它会在运行时被调用,被装饰的声明信息做为参数传入。

深入理解React中的setState

组件的状态是一种保存、处理和使用给定组件内部信息的方法,并允许你实现其自身的逻辑。状态本身其实是JavaScript中一个简单的对象(Plain Old Java[Script] Object),并且改变它是使组件重新进行渲染的几种方法之一

Vue子父组件方法互调

讲干货,不啰嗦,大家在做vue开发过程中经常遇到父组件需要调用子组件方法或者子组件需要调用父组件的方法的情况,现做一下总结,希望对大家有所帮助。设置子组件的ref

react totast组件开发

最近在主导有jquery类型转react技术栈-- 项目库中引入antd-mobile,但是由于totast组件不能满足要求...自己前端封装一个。分什么技术栈,全是垃圾,真正掌握基础

小程序自定义actionSheet组件

在微信小程序中,针对操作菜单的需求,官方文档提供了相应的api,如下图所示。但是小程序自带的操作菜单没有 “标题” 这么一个参数,不能在操作菜单的顶部显示自定义的标题

记录一次优雅的管理Vue全局组件自动注册和插件自动引入

随着项目的不断变大,可能有些人会把插件的引入和全局组件的注册都放到main.js中,导致后面main.js里面一大坨引入代码,看起来杂乱无比,也不利于后期进行维护,所以我们尽可能的让main.js看起来整洁些

使用vue.js的动态组件模板

组件并不总是具有相同的结构。有时需要管理许多不同的状态(注:指的是根据不同状态显示不同组件)。异步加载组件对此操作很有帮助。在 Scrumpy 中组件用于提醒、评论和附件等多个地方。

vue实现一个全局Message组件

不知道大家在用一些UI框架,比如Element-ui的时候,有没有觉得一些全局组件。this.$message(),this.Toast()等,用起来很爽。他们不像其他的组件,需要去导入,去注册。麻烦的很。

vue中8种组件通信方式

vue是数据驱动视图更新的框架, 所以对于vue来说组件间的数据通信非常重要,那么组件之间如何进行数据通信的呢?首先我们需要知道在vue中组件之间存在什么样的关系, 才更容易理解他们的通信方式

fly63.com版权所有,内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权,请与小编联系!情况属实本人将予以删除!

广告赞助文章投稿关于web前端网站点搜索站长推荐网站地图站长QQ:522607023

小程序专栏: 土味情话心理测试脑筋急转弯幽默笑话段子句子语录成语大全