目录
- 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 定义组件
① 以函数的形式来定义组件
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
② 以类(ES6 class)的形式来定义组件
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
1.3 渲染组件
组件可以当作 React 元素来用。而且我们可以通过 Props 来向组件中传递参数:
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
const element = <Welcome name="Sara" />;
ReactDOM.render(
element,
document.getElementById('root')
);
1.4 组合组件
组件可以互相引用,一个组件中可以在标签中使用其他组件。
例如, App
组件中就有三个 Welcome
组件:
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
) ,用来显示一条评论:
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
组件:
function Avatar(props) {
return (
<img className="Avatar"
src={props.user.avatarUrl}
alt={props.user.name}
/>
);
}
Comment
组件中的代码就变成了
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
组件:
function UserInfo(props) {
return (
<div className="UserInfo">
<Avatar user={props.user} />
<div className="UserInfo-name">
{props.user.name}
</div>
</div>
);
}
这样 Comment
组件中的代码就变得非常简单了:
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 一样(不可以修改传入的参数):
// This is a pure function
function sum(a, b) {
return a + b;
}
而不像 impure function(可以修改传入的参数):
// This function is impure because it changes its own input.
function withdraw(account, amount) {
account.total -= amount;
}
关于 props
使用的完整示例代码:
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);
规则:
- 组件名必须以大写字母开头。
- 所有的 React 组件都必须想 pure function 一样对待它的 props——不要在组件内部修改 props。
- 组件必须返回一个单独的根元素。就像在上文中 4.1 部分的示例代码一样,
App
组件返回时,通过一个<div>
标签将 3 个< Welcome />
标签包起来了。
延伸阅读:
- React Official Docs:Components and Props
- React Native 官方文档:属性(Props)
- 《React Native 入门与实战》