封装与解耦,组合与继承
在react的官方文档中,有这么一节Composition vs Inheritance,个人理解就是'组合与继承'.因为在当前的项目中,发现组件之间有多重继承的方式,不知羞耻的说,从事编程以来,还没有写过复杂的继承,顶多就是在prototype上面去扩展一些公共的方法,写的都是一些比较简单的继承.
当前项目的特点:
- 组件复杂,封装的很深,组件内部根据传参不同来if..else实现不同功能
- 各种函数,方法之间需要多重的参数传递,而且注释不明朗,不知前因后果的话,会非常困惑于代码段中的某一个参数或者方法.
个人理解
- 这里的组合并不是我们通常说的组件化之间的组合,这里说的组合,是一种***砖块 < 墙 < 毛坯房***的组合,砖块组合成墙,墙搭建成毛坯房,是三个层次之间的组合,不是1000块砖垒成墙,10面墙组成房子的那种同级组合.每个层级都需要其***内部各层级***提供的功能,最外层组件其实是***组合了内部几层***组件的特点,是has-a 和 is-a的区别.
- 最新的Angular 1.6.5, 和Angular2/4/5版本也是这种组合,具体可以看ngMaterial的示例,里面很好的应用了这种组合特性
react文档加个人理解
react拥有强大的组合模型,react官方强烈建议: 用***组合***而不是***继承***来实现代码复用
在这一节中,我们将会举几个例子,在以往的开发中常常是用***继承***去实现的,这里我们用***组合***的方式去实现这些功能
容器(Containment)
像***侧边栏(Sidebar)***或者***弹窗(Dialog)***之类的组件,在一开始定义的时候,是不知道它的内容具体要展示什么样子的(可能是一行文本,一段html代码,设置是一个react组件)
1.用children这个属性直接传入需要显示的内容
定义组件:
function FancyBorder(props) {
return(
<div className = {'FancyBorder FancyBorder-' + props.color} >
{props.children}
</div>
)
}
使用: 直接传入任意的符合jsx语法的内容
function WelcomeDialog() {
return (
<FancyBorder color="blue">
<h1 className="Dialog-title">
Welcome
</h1>
<p className="Dialog-message">
ContentContent
</p>
</FancyBorder>
)
}
如此一来,WelcomeDialog, 任何在<FancyBorder>标签中的内容都被传递到了FancyBorder,作为它的props.children,最终被渲染到页面中,你可以通过CodePen并打开控制台来看它的具体渲染结果.
然而很多时候,我们在一个组件中需要传入多个"子组件",当这些"子组件"很复杂的时候,很明显不能通过上面的方式囫囵一通的把所有内容都写在一起.这时候我们就需要通过props来实现
2. 通过props实现多个***占位符***
定义组件:
function SplitPane(props) {
return (
<div className="SplitPane">
<div className="SplitPane-left">
{props.left}
</div>
<div className="SplitPane-right">
{props.right}
</div>
</div>
);
}
使 用:
function App() {
return (
<SplitPane
left={
<Contacts />
}
right={
<Chat />
} />
);
}
在CodePen上查看,这里的<Contacts /> 和 <Chat />是一个jsx对象,同样你还可以传入其他类型的数据
3. 具象化(Specialization)
有时候我们需要把一个通用的组件(Dialog)更加的具象化(WelcomeDialog),然后去复用这个具象化后的组件(WelcomeDialog),在React中,同样可以通过***组合***的方式来实现
function Dialog(props) {
return (
<FancyBorder color="blue">
<h1 className="Dialog-title">
{props.title}
</h1>
<p className="Dialog-message">
{props.message}
</p>
</FancyBorder>
);
}
function WelcomeDialog() {
return (
<Dialog
title="Welcome"
message="Thank you for visiting our spacecraft!" />
);
}
注意!!! 这里***WelcomeDialog < Dialog < FancyBorder***,用了***三层组合***来实现一个特殊的欢迎框CodePen
更复杂的例子,以上都是通过function来生成的react组件,通过class定义的组件也没差
function Dialog(props) {
return (
<FancyBorder color="blue">
<h1 className="Dialog-title">
{props.title}
</h1>
<p className="Dialog-message">
{props.message}
</p>
{props.children}
</FancyBorder>
);
}
class SignUpDialog extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.handleSignUp = this.handleSignUp.bind(this);
this.state = {login: ''};
}
render() {
return (
<Dialog title="Mars Exploration Program"
message="How should we refer to you?">
<input value={this.state.login}
onChange={this.handleChange} />
<button onClick={this.handleSignUp}>
Sign Me Up!
</button>
</Dialog>
);
}
handleChange(e) {
this.setState({login: e.target.value});
}
handleSignUp() {
alert(`Welcome aboard, ${this.state.login}!`);
}
}
通过CodePen试一试,这里***SignUpDialog < Dialog < FancyBorder***三个组件组合
关于继承
Facebook大致意思是: 我们用react实现了成千上万个组件,但是没有发现任何组件需要使用***继承层次结构***来实现 最后,还是要强调一下,
- 这里的组合是***不同层次之间的组合***,不是***同层次之间的组合***
- props接收任意数据类型的传参,包括(原生JS数据类型,React元素,或者函数)