资讯专栏INFORMATION COLUMN

可靠React组件设计的7个准则之封装

yck / 876人阅读

摘要:组件可以处理其他组件的实例化为了避免破坏封装,请注意通过传递的内容。因此,将状态管理的父组件实例传递给子组件会破坏封装。让我们改进两个组件的结构和属性,以便恢复封装。组件的可重用性和可测试性显著增加。

翻译:刘小夕

原文链接:https://dmitripavlutin.com/7-...

原文的篇幅非常长,不过内容太过于吸引我,还是忍不住要翻译出来。此篇文章对编写可重用和可维护的React组件非常有帮助。但因为篇幅实在太长,我对文章进行了分割,本篇文章重点阐述 封装。因本人水平有限,文中部分翻译可能不够准确,如果您有更好的想法,欢迎在评论区指出。

更多文章可戳: https://github.com/YvetteLau/...

———————————————我是一条分割线————————————————

封装
一个封装组件提供 props 控制其行为而不是暴露其内部结构。

耦合是决定组件之间依赖程度的系统特性。根据组件的依赖程度,可区分两种耦合类型:

当应用程序组件对其他组件知之甚少或一无所知时,就会发生松耦合。

当应用程序组件知道彼此的许多详细信息时,就会发生紧耦合。

松耦合是我们设计应用结构和组件之间关系的目标。

松耦合应用(封装组件)

松耦合会带来以下好处:

可以在不影响应用其它部分的情况下对某一块进行修改。、

任何组件都可以替换为另一种实现

在整个应用程序中实现组件复用,从而避免重复代码

独立组件更容易测试,增加了测试覆盖率

相反,紧耦合的系统会失去上面描述的好处。主要缺点是很难修改高度依赖于其他组件的组件。即使是一处修改,也可能导致一系列的依赖组件需要修改。

紧耦合应用(组件无封装)

封装信息隐藏 是如何设计组件的基本原则,也是松耦合的关键。

信息隐藏

封装良好的组件隐藏其内部结构,并提供一组属性来控制其行为。

隐藏内部结构是必要的。其他组件没必要知道或也不依赖组件的内部结构或实现细节。

React 组件可能是函数组件或类组件、定义实例方法、设置 ref、拥有 state 或使用生命周期方法。这些实现细节被封装在组件内部,其他组件不应该知道这些细节。

隐藏内部结构的组件彼此之间的依赖性较小,而降低依赖度会带来松耦合的好处。

通信

细节隐藏是隔离组件的关键。此时,你需要一种组件通信的方法:propsporps 是组件的输入。

建议 prop 的类型为基本数据(例如,stringnumberboolean):

;

必要时,使用复杂的数据结构,如对象或数组:

prop 可以是一个事件处理函数和异步函数:

prop 甚至可以是一个组件构造函数。组件可以处理其他组件的实例化:

function If({ component: Component, condition }) {
    return condition ?  : null;
}
  

为了避免破坏封装,请注意通过 props 传递的内容。给子组件设置 props 的父组件不应该暴露其内部结构的任何细节。例如,使用 props 传输整个组件实例或 refs 都是一个不好的做法。

访问全局变量同样也会对封装产生负面影响。

案例研究:封装修复

组件的实例和状态对象是封装在组件内部的实现细节。因此,将状态管理的父组件实例传递给子组件会破坏封装。

我们来研究一下这种情况。

一个简单的应用程序显示一个数字和两个按钮。第一个按钮增加数值,第二个按钮减少数值:

这个应用由两个组件组成:.

numberstate 对象, 负责 将这个数字渲染到页面。

// 问题: 封装被破坏
class App extends Component {
    constructor(props) {
        super(props);
        this.state = { number: 0 };
    }

    render() {
        return (
            
{this.state.number}
); } }

负责渲染按钮,并为其设置事件处理函数,当用户点击按钮时,父组件的状态将会被更新:number 加1或者减1((updateNumber()方法`)

// 问题: 使用父组件的内部结构
class Controls extends Component {
    render() {
        return (
            
); } updateNumber(toAdd) { this.props.parent.setState(prevState => ({ number: prevState.number + toAdd })); } }

当前的实现有什么问题?

第一个问题是: 的封装被破坏,因为它的内部结构在应用中传递。 错误地允许 直接去修改其 state

第二个问题是: 子组件 Controls 知道了太多父组件 的内部细节,它可以访问父组件的实例,知道父组件是一个有状态组件,知道父组件的 state 对象的细节(知道 number 是父组件 state 的属性),并且知道怎么去更新父组件的 state.

一个麻烦的结果是: 将很难测试和重用。对 结构的细微修改会导致需要对 进行修改(对于更大的应用程序,也会导致类似耦合的组件需要修改)。

解决方案是设计一个方便的通信接口,考虑到松耦合和封装。让我们改进两个组件的结构和属性,以便恢复封装。

只有组件本身应该知道它的状态结构。 的状态管理应该从 updateNumber()方法)移到正确的位置:即 组件中。

被修改为 设置属性 onIncreaseonDecrease。这些是更新 状态的回调函数:

// 解决: 恢复封装
class App extends Component {
    constructor(props) {
        super(props);
        this.state = { number: 0 };
    }

    render() {
        return (
            
{this.state.number} this.updateNumber(+1)} onDecrease={() => this.updateNumber(-1)} />
); } updateNumber(toAdd) { this.setState(prevState => ({ number: prevState.number + toAdd })); } }

现在, 接收用于增加和减少数值的回调,注意解耦和封装恢复时: 不再需要访问父组件实例。也不会直接去修改父组件的状态。

而且, 被修改为了一个函数式组件:

// 解决方案: 使用回调函数去更新父组件的状态
function Controls({ onIncrease, onDecrease }) {
    return (
        
); }

组件的封装已经恢复,状态由其本身管理,也应该如此。

此外, 不在依赖 的实现细节,onIncreaseonDecrease 在按钮被点击的时候调用, 不知道(也不应该知道)这些回调的内部实现。

组件的可重用性和可测试性显著增加。

的复用变得很容易,因为它除了需要回调,没有其它依赖。测试也变得简单,只需验证单击按钮时,回调是否执行。

最后谢谢各位小伙伴愿意花费宝贵的时间阅读本文,如果本文给了您一点帮助或者是启发,请不要吝啬你的赞和Star,您的肯定是我前进的最大动力。https://github.com/YvetteLau/...

关注小姐姐的公众号,加入交流群。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/106577.html

相关文章

  • 可靠React组件设计7准则终篇

    摘要:单元测试不仅涉及早期错误检测。当组件的架构设计很脆弱时,就会变得难以测试,而当组件难以测试的时候,你大概念会跳过编写单元测试的过程,最终的结果就是组件未测试。可测试性是确定组件结构良好程度的实用标准。可复用的组件是精心设计的系统的结果。 翻译:刘小夕原文链接:https://dmitripavlutin.com/7-... 本篇文章重点阐述可测试和富有意义。因水平有限,文中部分翻译可...

    jasperyang 评论0 收藏0
  • 可靠React组件设计7准则组合和复用

    摘要:幸运的是,组合易于理解。组件的组合是自然而然的。高效用户界面可组合的层次结构,因此,组件的组合是一种构建用户界面的有效的方式。这个原则建议避免重复。只有一个组件符合单一责任原则并且具有合理的封装时,它是可复用的。 翻译:刘小夕原文链接:https://dmitripavlutin.com/7-... 原文的篇幅非常长,不过内容太过于吸引我,还是忍不住要翻译出来。此篇文章对编写可重用和...

    Amos 评论0 收藏0
  • 可靠React组件设计7准则SRP

    摘要:编写组件时要考虑的基本准则是单一职责原则。这些更改通常要求组件在隔离状态下易于修改这也是的目标。解决多重责任问题需要将分割为两个组件和。组件之间的通信是通过实现。更改的唯一原因是修改表单字段。 翻译:刘小夕原文链接:https://dmitripavlutin.com/7-... 原文的篇幅非常长,不过内容太过于吸引我,还是忍不住要翻译出来。此篇文章对编写可重用和可维护的React组...

    Charles 评论0 收藏0
  • 函数式编程与面向对象编程[5]:编程本质

    摘要:函数式编程与面向对象编程编程的本质之剑目录编程的本质读到两篇文章写的不错综合摘录一下复合是编程的本质函数式程序员在洞察问题方面会遵循一个奇特的路线。在面向对象编程中,类或接口的声明就是表面。 函数式编程与面向对象编程[5]:编程的本质 之剑 2016.5.6 01:26:31 编程的本质 读到两篇文章,写的不错, 综合摘录一下 复合是编程的本质 函数式程序员在洞察问题方面会遵循...

    miracledan 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<