Composition vs Inheritance - 组合对比继承
React有一个强大的组合模型,并且我们推荐使用组合来代替继承,在组件间重复使用代码。
在这一章节,我们将考虑React新手开发者经常碰到的几个关于继承的问题,并展示我们如何使用组合来解决这些问题。
containment - 控制
有些组件提前不知道它们的子组件。这对于像 'Sidebar' 或 'Dialog' 的组件是特别平常的。
我们推荐这些组件使用特殊的 'children' props,来直接传递子元素到它们的输出中:
任何在 '<FancyBorder>' JSX 标签内的元素,传递给 'FancyBorder' 组件,作为 'children' props(也就是 props.children = 标签内的元素)。由于 'FancyBorder' 在 '<div>' 内渲染 '{props.children}',传递的元素会出现在最终的输出中(组件渲染,输出必须有一个 '根元素',这里 '<div>' 就是根元素,如果没有 'div' 就会报错!)
上面这种情况不是很常见,很多时候,我们需要的是在一个组件的多个地方,使用这种嵌套。在这种情况下,我们得自己定义规则来代替使用 'children':
React元素,像:'<Contacts />'和'<Chat />' 只是对象,所有你能像任何其他数据一样传递它们给 props
specialization - 特殊化(可理解为:特例)
有时我们认为组件是其他组件的 "特殊实例"。例如,我们可能说 'WelcomeDialog' 是 'Dialog' 的一类特殊实例:
组合对于类定义的组件,工作的一样出色。
so what about inheritance? - 那么继承呢?
在Facebook,我们在成千上万点React组件,但是我们未发现任何案例,我们可以推荐来创建组件继承层级结构。
props和组合给了你足够的灵活性,来自定义一个组件的外观和行为,使用一种明确和安全的方式。记住,组件可以接受任意props,包括原始值、React元素或函数。
如果你想在组件之间重用非UI功能,我们建议提取它到一个单独的js模块。组件可以导入它,使用函数、对象或类,而不会扩展它。
React有一个强大的组合模型,并且我们推荐使用组合来代替继承,在组件间重复使用代码。
在这一章节,我们将考虑React新手开发者经常碰到的几个关于继承的问题,并展示我们如何使用组合来解决这些问题。
containment - 控制
有些组件提前不知道它们的子组件。这对于像 'Sidebar' 或 'Dialog' 的组件是特别平常的。
我们推荐这些组件使用特殊的 'children' props,来直接传递子元素到它们的输出中:
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">
Thank you for visiting our spacecraft!
</p>
</FancyBorder>
);
}
任何在 '<FancyBorder>' JSX 标签内的元素,传递给 'FancyBorder' 组件,作为 'children' props(也就是 props.children = 标签内的元素)。由于 'FancyBorder' 在 '<div>' 内渲染 '{props.children}',传递的元素会出现在最终的输出中(组件渲染,输出必须有一个 '根元素',这里 '<div>' 就是根元素,如果没有 'div' 就会报错!)
上面这种情况不是很常见,很多时候,我们需要的是在一个组件的多个地方,使用这种嵌套。在这种情况下,我们得自己定义规则来代替使用 'children':
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 />}
/>
);
}
React元素,像:'<Contacts />'和'<Chat />' 只是对象,所有你能像任何其他数据一样传递它们给 props
specialization - 特殊化(可理解为:特例)
有时我们认为组件是其他组件的 "特殊实例"。例如,我们可能说 'WelcomeDialog' 是 'Dialog' 的一类特殊实例:
function Dialog(props) {
return (
<FancyBorder color="blue">
<h1 className="Dialog-title">
{props.title}
</h1>
<p className="Dialog-message">
{props.message}
</p>
</FancyBorder>
);
}
// 是 'Dialog' 的一种情况而已
function WelcomeDialog() {
return (
<Dialog
title="Welcome"
message="Thank you for visiting our spacecraft!"
/>
);
}
组合对于类定义的组件,工作的一样出色。
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(pros) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.handleSignUp = this.handleSignUp.bind(this);
this.state = {login: ''};
}
handleChange(e) {
this.setState({login: e.target.value});
}
handleSignUp(e) {
alert(`Welcome aboard, ${this.state.login}!`);
}
rend() {
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>
);
}
}
so what about inheritance? - 那么继承呢?
在Facebook,我们在成千上万点React组件,但是我们未发现任何案例,我们可以推荐来创建组件继承层级结构。
props和组合给了你足够的灵活性,来自定义一个组件的外观和行为,使用一种明确和安全的方式。记住,组件可以接受任意props,包括原始值、React元素或函数。
如果你想在组件之间重用非UI功能,我们建议提取它到一个单独的js模块。组件可以导入它,使用函数、对象或类,而不会扩展它。