react----组件封装,更好的封装组件的方式(整理)

原文链接:https://mp.weixin.qq.com/s/bC36yH0Uor9MiVXKNCwNbA
目前我只是整理了一下原文中我理解的地方。

(一)耦合是决定组件之间依赖程度的系统特性。根据组件的依赖程度,可区分两种耦合类型:
(1)当应用程序组件对其他组件知之甚少或一无所知时,就会发生松耦合。
(2)当应用程序组件知道彼此的许多详细信息时,就会发生紧耦合。

(二)松耦合设计应用结构和组件之间关系的目标。封装或 信息隐 是如何设计组件的基本原则,也是松耦合的关键。
松耦合应用(即封装组件),松耦合的好处:
(1)可以在不影响应用其它部分的情况下对某一块进行修改。、
(2)任何组件都可以替换为另一种实现
(3)在整个应用程序中实现组件复用,从而避免重复代码
(4)独立组件更容易测试,增加了测试覆盖率
紧耦合应用(组件无封装):这样的话,其实是不利于组件的复用的
(三)当组件进行封装以后,主要的通信方式就是通过props
为了避免破坏封装,请注意通过 props 传递的内容。给子组件设置 props 的父组件不应该暴露其内部结构的任何细节。例如,使用 props 传输整个组件实例或 refs 都是一个不好的做法。
(四)案例实现

class App extends React.Component {
    constructor(props) {
        super(props);
        this.state = { number: 0 };
    }

    render() {
        return (
            <div className="app">
                <span className="number">{this.state.number}</span>
                <Controls parent={this} />
            </div>
        );
    }
}

class Controls extends React.Component {
    render() {
        return (
            <div className="controls">
                <button onClick={() => this.updateNumber(+1)}>
                    Increase
          </button>
                <button onClick={() => this.updateNumber(-1)}>
                    Decrease
          </button>
            </div>
        );
    }

    updateNumber(toAdd) {
        this.props.parent.setState(prevState => ({
            number: prevState.number + toAdd
        }));
    }
}

ReactDOM.render(<App />, document.getElementById('root')); 

当前的实现有什么问题?
第一个问题是:<App> 的封装被破坏,因为它的内部结构在应用中传递。<App> 错误地允许 <Controls> 直接去修改其 state
第二个问题是: 子组件 Controls 知道了太多父组件 的内部细节,它可以访问父组件的实例,知道父组件是一个有状态组件,知道父组件的 state 对象的细节(知道 number 是父组件 state 的属性),并且知道怎么去更新父组件的 state.
这样就会导致:<Controls> 将很难测试和重用。对 <App> 结构的细微修改会导致需要对 <Controls> 进行修改(对于更大的应用程序,也会导致类似耦合的组件需要修改)。
解决以上问题

// 解决: 恢复封装
 class App extends Component {
     constructor(props) {
         super(props);
         this.state = { number: 0 };
     }
 
     render() {
         return (
             <div className="app">
                 <span className="number">{this.state.number}</span>
                 <Controls
                     onIncrease={() => this.updateNumber(+1)}
                     onDecrease={() => this.updateNumber(-1)}
                 />
             </div>
         );
     }
 
     updateNumber(toAdd) {
         this.setState(prevState => ({
             number: prevState.number + toAdd
         }));
     }
 }

// 解决方案: 使用回调函数去更新父组件的状态,使用父组件本身的方法去更新父组件本身的状态
function Controls({ onIncrease, onDecrease }) {
    return (
        <div className="controls">
            <button onClick={onIncrease}>Increase</button>
            <button onClick={onDecrease}>Decrease</button>
        </div>
    );
}

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

此外,<Controls> 不在依赖 <App> 的实现细节,onIncreaseonDecrease 在按钮被点击的时候调用,<Controls> 不知道(也不应该知道)这些回调的内部实现。
<Controls> 组件的可重用性和可测试性显著增加。
<Controls> 的复用变得很容易,因为它除了需要回调,没有其它依赖。测试也变得简单,只需验证单击按钮时,回调是否执行。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值