Skip to content

Commit

Permalink
react component and props
Browse files Browse the repository at this point in the history
Former-commit-id: a25fef6
Former-commit-id: 61d9a64
  • Loading branch information
hstarorg committed Apr 14, 2017
1 parent 780347a commit 5f90dce
Showing 1 changed file with 255 additions and 0 deletions.
255 changes: 255 additions & 0 deletions React面面观/【译】快速起步-组件与属性.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,255 @@
---
title: 快速起步-组件与属性
date: 2017-4-14 16:01:04
version: 15.5.0
---

# 组件与属性

组件允许您将UI拆分为多个独立的,可重用的部分。

概念上,组件就类似于 `JavaScript` 函数。它们接收任意的输入(`props`),返回用于描述屏幕显示内容的 `React elements`

## 函数式组件和类组件

最简单定义组件的方式,是编写一个 `JavaScript` 函数:

```js
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
```
这个函数是一个合法的组件,因为它接收包含数据的单个 `props` 对象参数,返回了一个 `React elements`。我们称这种用JavaScript函数定义的组件为函数式组件。

你也可以使用 [ES6 class](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Classes) 来定义组件:

```js
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
```

上述两个组件在视图展示上是等同的。

[下一章节](【译】快速起步-状态和生命周期.md) 我们会讨论类组件的一些附加特性。在这之前,我们先使用函数式组件来简化演示。

## 渲染组件

之前,我们仅仅遇到表示DOM标签的 `React elements`

```js
const element = <div />;
```

然而,元素也可以表示用户定义的组件:

```js
const element = <Welcome name="Sara" />;
```
`React` 发现元素表示一个用户定义的组件时,它将 `JSX` 属性作为单个对象传递给组件。我们称之为 `props`

例如,以下代码在页面上渲染 "Hello, Sara":

```js{1,5}
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
const element = <Welcome name="Sara" />;
ReactDOM.render(
element,
document.getElementById('root')
);
```

[CodePen Demo](http://codepen.io/gaearon/pen/YGYmEG?editors=0010)

我们回顾下这个例子中发生了什么:

1. 使用 `<Welcome name="Sara" />` 元素调用 `ReactDOM.render()`
2. React 将 `{name: 'Sara'}` 作为属性调用 `Welcome` 组件。
3. `Welcome` 组件将 `<h1>Hello, Sara</h1>` 元素作为结果返回。
4. React DOM 使用 `<h1>Hello, Sara</h1>` 来更新DOM。

>**警告:**
>
>总是用大写字母开头命名自定义组件
>
>例如, `<div />` 表示一个DOM标签,但是 `<Welcome />` 表示一个组件,且需要作用域中存在 `Welcome` 变量。
## 复合组件

组件可以在其输出中引用其他组件。这使我们可以对不同级别的实现抽象为相同的组件。在 `React` 中,按钮、表单、对话框,屏幕都通常被抽象为组件。

例如,我们可以创建 `App` 组件来渲染多个 `Welcome` 组件:

```js{8-10}
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
function App() {
return (
<div>
<Welcome name="Sara" />
<Welcome name="Cahal" />
<Welcome name="Edite" />
</div>
);
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
```

[CodePen Demo](http://codepen.io/gaearon/pen/KgQKPr?editors=0010)

通常,新的React应用程序在最顶层都会有一个 `App` 组件。然而,如果你集成 `React` 到一个现有的应用程序,你可以在内部先使用像 `Button` 这样的小部件,然后逐步的替换到最顶层。

>**警告:**
>
>组件必须返回单个根元素。这是为什么我们用 `<div>` 来包含多个 `<Welcome />` 组件。
## 提取组件

不要害怕将组件分成更小的组件。

例如,思考这个 `Comment` 组件:

```js
function Comment(props) {
return (
<div className="Comment">
<div className="UserInfo">
<img className="Avatar"
src={props.author.avatarUrl}
alt={props.author.name}
/>
<div className="UserInfo-name">
{props.author.name}
</div>
</div>
<div className="Comment-text">
{props.text}
</div>
<div className="Comment-date">
{formatDate(props.date)}
</div>
</div>
);
}
```

[CodePen Demo](http://codepen.io/gaearon/pen/VKQwEo?editors=0010)

它接收 `author`(对象类型),`text`(字符串)和 `date`(日期) 作为属性,然后在社交网站上呈现一个评论。

由于多层嵌套,这个组件很难变化,且很难重用它其中的各个部分。我们可以从中提取几个组件。

首先,我们提取 `Avatar` 组件:

```js{3-6}
function Avatar(props) {
return (
<img className="Avatar"
src={props.user.avatarUrl}
alt={props.user.name}
/>
);
}
```

`Avatar` 不需要知道谁会渲染它。这也是为什么我们使用 `user` 这个更通用的属性名称来替代 `author`

我们建议从组件自身的角度来命名属性,而不是它的使用者。

我们现在已经稍微简化了一下 `Comment` 组件:

```js{5}
function Comment(props) {
return (
<div className="Comment">
<div className="UserInfo">
<Avatar user={props.author} />
<div className="UserInfo-name">
{props.author.name}
</div>
</div>
<div className="Comment-text">
{props.text}
</div>
<div className="Comment-date">
{formatDate(props.date)}
</div>
</div>
);
}
```

下一步,我们将提取 `UserInfo` 组件,用于在用户名旁边显示 `Avator`

```js{3-8}
function UserInfo(props) {
return (
<div className="UserInfo">
<Avatar user={props.user} />
<div className="UserInfo-name">
{props.user.name}
</div>
</div>
);
}
```

这让我们进一步简化了 `Comment` 组件:

```js{4}
function Comment(props) {
return (
<div className="Comment">
<UserInfo user={props.author} />
<div className="Comment-text">
{props.text}
</div>
<div className="Comment-date">
{formatDate(props.date)}
</div>
</div>
);
}
```

[CodePen Demo](http://codepen.io/gaearon/pen/rrJNJY?editors=0010)

提取组件可能是看起来很繁琐的工作,但是在较大的应用程序中,可重用的组件能够付出更小的代价。
如果您的UI的一部分使用了几次(按钮,面板,头像)或者它自身就很复杂(App, Comment),它们则是拆分出可重用组件的最佳候选人,这是一个相当实用的经验法则。

## 属性是只读的

当你定义一个组件时,它不应该修改自己的 `props`。思考下面的 `sum` 函数。

```js
function sum(a, b) {
return a + b;
}
```

这些不会修改输入参数,且当输入参数相同时,总是返回相同结果的函数被称之为 [纯函数](https://en.wikipedia.org/wiki/Pure_function)

相比之下,以下的函数是不纯的,因为它改变了自己的输入:

```js
function withdraw(account, amount) {
account.total -= amount;
}
```

`React` 非常灵活,但是也有一个严格的规则:

**所有的React组件必须像纯函数那样使用 `props`(也就是不要在组件内部修改 `props`**

当然,应用程序的UI是动态的,可以随时间的推移而变化。在 [下一节](【译】快速起步-状态和生命周期.md) 中,我们将介绍新的概念 `state``state` 允许React组件根据用户操作,网络响应以及其他随时间推移产生的变化来修改组件输出,而不会违背该规则。

0 comments on commit 5f90dce

Please sign in to comment.