Skip to content

Commit

Permalink
react Composition vs Inheritance
Browse files Browse the repository at this point in the history
Former-commit-id: 05ed2ec
Former-commit-id: 68f0b3f
  • Loading branch information
hstarorg committed Apr 26, 2017
1 parent 78ef5af commit e966416
Showing 1 changed file with 170 additions and 0 deletions.
170 changes: 170 additions & 0 deletions React面面观/【译】快速起步-组合与继承.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
---
title: 快速起步-组合与继承
date: 2017-4-26 13:19:51
version: 15.5.0
---

# 组合 VS. 继承

`React` 具有很强大的组合模型,我们推荐使用组合而不是继承来重用组件之间的代码。

在这一章节中,我们将思考一些React新手通常遇到的问题,并展示如何使用组合来解决它们。

## 容器

一些组件并不能提前知道它们的子集。这在通用盒子组件,如 `Sidebar` 或者 `Dialog` 上尤其常见。

我们推荐这类组件使用特定的 `children` 属性,将子元素传递到其输出中:

```js{4}
function FancyBorder(props) {
return (
<div className={'FancyBorder FancyBorder-' + props.color}>
{props.children}
</div>
);
}
```

这允许其他组件通过嵌套JSX传递任意的子集到组件内部:

```js{4-9}
function WelcomeDialog() {
return (
<FancyBorder color="blue">
<h1 className="Dialog-title">
Welcome
</h1>
<p className="Dialog-message">
Thank you for visiting our spacecraft!
</p>
</FancyBorder>
);
}
```

[Try it on CodePen.](http://codepen.io/gaearon/pen/ozqNOV?editors=0010)

任何JSX标签 `<FancyBorder>` 内部的内容,都会作为 `children` 属性传递给 `FancyBorder` 组件。由于 `FancyBorder` 会在 `<div>` 中渲染 `{props.children}`,传递的元素将会出现在最终输出中。

虽然这不太常见,但有时您可能需要在组件中设置多个“孔”(holes,译者注:插槽)。在这种情况下,您可以采用您自己的约定,而不是使用 `children`

```js{5,8,18,21}
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 />
} />
);
}
```

[Try it on CodePen.](http://codepen.io/gaearon/pen/gwZOJp?editors=0010)

`<Contacts />``<Chat />` 这样的React元素只是对象,所以你可以像传递其他数据一样将其作为属性传递。

## 具象化

有时我们认为某些组件是其他组件的“特殊情况”。比如,我们认为 `WelcomeDialog` 是一个特殊的 `Dialog`

在React中,这也可以通过组合来实现,其中更“特殊”的组件会渲染更“通用”的组件,并且使用属性来配置通用组件:

```js{5,8,16-18}
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!" />
);
}
```

[Try it on CodePen.](http://codepen.io/gaearon/pen/kkEaOZ?editors=0010)

组合对应定义为类的组件同样适用:

```js{10,27-31}
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}!`);
}
}
```

[Try it on CodePen.](http://codepen.io/gaearon/pen/gwZbYa?editors=0010)

## 那么继承呢?

在Facebook,我们在数以千计的组件中使用React,并且我们没有发现任何用例会要求我们创建组件继承层次结构。

当你需要用安全的方式定制组件的外观和形式时,属性和组合给了你所有的灵活性。 请记住,组件接受任意props,包括原始值、React元素或函数。

如果你想在组件之中重用非UI的功能,我们建议您将其提取到单独的 `JavaScript` 模块中。组件可以导入它,并在不扩展它的情况下,使用哪些函数,对象或者是类。

0 comments on commit e966416

Please sign in to comment.