【译】快速起步-组件与属性
react version: 15.5.0
组件与属性
组件允许您将UI拆分为多个独立的,可重用的部分。
概念上,组件就类似于 JavaScript
函数。它们接收任意的输入(props
),返回用于描述屏幕显示内容的 React elements
。
函数式组件和类组件
最简单定义组件的方式,是编写一个 JavaScript
函数:
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
这个函数是一个合法的组件,因为它接收包含数据的单个 props
对象参数,返回了一个 React elements
。我们称这种用JavaScript函数定义的组件为函数式组件。
你也可以使用 ES6 class 来定义组件:
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
上述两个组件在视图展示上是等同的。
在 下一章节 我们会讨论类组件的一些附加特性。在这之前,我们先使用函数式组件来简化演示。
渲染组件
之前,我们仅仅遇到表示DOM标签的 React elements
:
const element = <div />;
然而,元素也可以表示用户定义的组件:
const element = <Welcome name="Sara" />;
当 React
发现元素表示一个用户定义的组件时,它将 JSX
属性作为单个对象传递给组件。我们称之为 props
。
例如,以下代码在页面上渲染 "Hello, Sara":
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
const element = <Welcome name="Sara" />;
ReactDOM.render(
element,
document.getElementById('root')
);
我们回顾下这个例子中发生了什么:
- 使用
<Welcome name="Sara" />
元素调用ReactDOM.render()
。 - React 将
{name: 'Sara'}
作为属性调用Welcome
组件。 Welcome
组件将<h1>Hello, Sara</h1>
元素作为结果返回。- React DOM 使用
<h1>Hello, Sara</h1>
来更新DOM。
警告:
总是用大写字母开头命名自定义组件
例如,
<div />
表示一个DOM标签,但是<Welcome />
表示一个组件,且需要作用域中存在Welcome
变量。
复合组件
组件可以在其输出中引用其他组件。这使我们可以对不同级别的实现抽象为相同的组件。在 React
中,按钮、表单、对话框,屏幕都通常被抽象为组件。
例如,我们可以创建 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')
);
通常,新的React应用程序在最顶层都会有一个 App
组件。然而,如果你集成 React
到一个现有的应用程序,你可以在内部先使用像 Button
这样的小部件,然后逐步的替换到最顶层。
警告:
组件必须返回单个根元素。这是为什么我们用
<div>
来包含多个<Welcome />
组件。
提取组件
不要害怕将组件分成更小的组件。
例如,思考这个 Comment
组件:
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>
);
}
它接收 author
(对象类型),text
(字符串)和 date
(日期) 作为属性,然后在社交网站上呈现一个评论。
由于多层嵌套,这个组件很难变化,且很难重用它其中的各个部分。我们可以从中提取几个组件。
首先,我们提取 Avatar
组件:
function Avatar(props) {
return (
<img className="Avatar"
src={props.user.avatarUrl}
alt={props.user.name}
/>
);
}
Avatar
不需要知道谁会渲染它。这也是为什么我们使用 user
这个更通用的属性名称来替代 author
。
我们建议从组件自身的角度来命名属性,而不是它的使用者。
我们现在已经稍微简化了一下 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>
);
}
下一步,我们将提取 UserInfo
组件,用于在用户名旁边显示 Avator
:
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>
);
}
提取组件可能是看起来很繁琐的工作,但是在较大的应用程序中,可重用的组件能够付出更小的代价。
如果您的UI的一部分使用了几次(按钮,面板,头像)或者它自身就很复杂(App, Comment),它们则是拆分出可重用组件的最佳候选人,这是一个相当实用的经验法则。
属性是只读的
当你定义一个组件时,它不应该修改自己的 props
。思考下面的 sum
函数。
function sum(a, b) {
return a + b;
}
这些不会修改输入参数,且当输入参数相同时,总是返回相同结果的函数被称之为 纯函数。
相比之下,以下的函数是不纯的,因为它改变了自己的输入:
function withdraw(account, amount) {
account.total -= amount;
}
React
非常灵活,但是也有一个严格的规则:
所有的React组件必须像纯函数那样使用 props
(也就是不要在组件内部修改 props
)
当然,应用程序的UI是动态的,可以随时间的推移而变化。在 下一节 中,我们将介绍新的概念 state
。state
允许React组件根据用户操作,网络响应以及其他随时间推移产生的变化来修改组件输出,而不会违背该规则。