-
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
255 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,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组件根据用户操作,网络响应以及其他随时间推移产生的变化来修改组件输出,而不会违背该规则。 |