目录

  • 1.组件(Components)
    • 1.1 什么是组件
    • 1.2 定义组件
    • 1.3 渲染组件
    • 1.4 组合组件
    • 1.5 封装组件
  • 2.属性(Props)

1. 组件(Components)

1.1 什么是组件

组件能让你将 UI 拆分成各个独立的、可复用的子单元。组件就像 JavaScript 函数一样,接受参数(也就是 props),返回屏幕上要渲染的 React 元素。各个组件内部维护自己的状态和 UI,当状态发生改变时,React 会自动重新渲染整个组件,多个组件一起协作共同构成了 React 应用。

1.2 定义组件

① 以函数的形式来定义组件

1
2
3
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}

② 以类(ES6 class)的形式来定义组件

1
2
3
4
5
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}

1.3 渲染组件

组件可以当作 React 元素来用。而且我们可以通过 Props 来向组件中传递参数:

1
2
3
4
5
6
7
8
9
 function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}

const element = <Welcome name="Sara" />;
ReactDOM.render(
element,
document.getElementById('root')
);

1.4 组合组件

组件可以互相引用,一个组件中可以在标签中使用其他组件。

例如, App 组件中就有三个 Welcome 组件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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')
);

1.5 封装组件

通过将可重用的代码封装成一个独立的组件,可以提高代码的复用性和可读性。

什么时候需要封装组件?
① 大量的重复 UI 代码;
② 一个组件内部有太多的内容,相当复杂时,就需要抽取一部分代码出来。

举个例子,我们现在有一个 Comment 组件,通过 props 接收了三个参数 author (object), text (string), 和 date (date) ,用来显示一条评论:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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>
);
}

很显然,这里的代码嵌套太多,难以阅读,而且里面的一些代码不能被重用。所以,我们可以尝试抽取一些代码进行组件封装。
第一步,我们先封装一个 Avatar 组件:

1
2
3
4
5
6
7
8
function Avatar(props) {
return (
<img className="Avatar"
src={props.user.avatarUrl}
alt={props.user.name}
/>
);
}

Comment 组件中的代码就变成了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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>
);
}

即便这样,Comment 中的代码感觉还是有点多,我们还可以再进一步抽取封装一个 UserInfo 组件:

1
2
3
4
5
6
7
8
9
10
function UserInfo(props) {
return (
<div className="UserInfo">
<Avatar user={props.user} />
<div className="UserInfo-name">
{props.user.name}
</div>
</div>
);
}

这样 Comment 组件中的代码就变得非常简单了:

1
2
3
4
5
6
7
8
9
10
11
12
13
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>
);
}

2. 属性(Props)

什么是属性?大多数组件在创建时就可以使用各种参数来进行定制,用于定制的这些参数就称为属性(props)。

属性是用来给外部向组件内部传值的,组件的内部通过读取 props 来决定如何展示以及处理一些逻辑。

属性是只读的,不要试图在组件内部修改外部传递进来的 props。

React 组件就像 pure function 一样(不可以修改传入的参数):

1
2
3
4
// This is a pure function
function sum(a, b) {
return a + b;
}

而不像 impure function(可以修改传入的参数):

1
2
3
4
// This function is impure because it changes its own input.
function withdraw(account, amount) {
account.total -= amount;
}

关于 props 使用的完整示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import React, { Component } from 'react';
import { AppRegistry, Text, View } from 'react-native';

class Greeting extends Component {
render() {
return (
<Text>Hello {this.props.name}!</Text>
);
}
}

class LotsOfGreetings extends Component {
render() {
return (
<View style={{alignItems: 'center'}}>
<Greeting name='Rexxar' />
<Greeting name='Jaina' />
<Greeting name='Valeera' />
</View>
);
}
}

AppRegistry.registerComponent('LotsOfGreetings', () => LotsOfGreetings);

规则:

  1. 组件名必须以大写字母开头。
  2. 所有的 React 组件都必须想 pure function 一样对待它的 props——不要在组件内部修改 props。
  3. 组件必须返回一个单独的根元素。就像在上文中 4.1 部分的示例代码一样,App 组件返回时,通过一个 <div> 标签将 3 个 < Welcome /> 标签包起来了。

延伸阅读: