-
Notifications
You must be signed in to change notification settings - Fork 67
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
170 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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` 模块中。组件可以导入它,并在不扩展它的情况下,使用哪些函数,对象或者是类。 |