组件和属性
组件使 UI 分离为独立可服用的块,可隔离思考每一个块。这页介绍组件理念。在此查阅 组件 API 参考。
概念上讲,组件与 JavaScript 函数相像。他们接受任意输入(称为 “props”) 然后返回描述屏幕上显示的 React elements 。
函数组件、类组件
定义一个组件最简单的方式是写一个 JavaScript 函数:
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
这个函数是一个有效的 React component 因为它接受了单一的 “props”(这个是 properties 的缩写)对象数据参数且返回了一个 React element. 我们称这样的组件为 “functional” 因为他们就是 JavaScript functions 的字面含义。
也可以使用 ES6 class 来定义一个组件:
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
以上两种组件对 React 来说没有区别。
classes 有额外的特点我们[下一部分]()讨论。在那之前,简明旗舰我们使用函数组件。
渲染组件
之前,我们只鼓励 React elements 呈现 DOM 标签:
const element = <div />;
然而, elements 也能呈现自定义组件:
const element = <Welcome name="Sara" />;
当 React 发现一个 element 呈现用户自定义组件,它会将 JSX 属性做为单个对象传递到这个组件。 我们称这个对象 “props”.
例如: 这个代码在页面渲染出 “Hello, Sara”:
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
扼要重述例子中发生了什么:
- 调用 ReactDOM.render() 和 <Welcome name=”Sara” /> element.
- 基于 {name: ‘Sara’} 作为props React 调用 Welcome 组件。
- Welcome 组件返回结果 <h1>Hello, Sara</h1> element。
- ReactDOM 高效更新 DOM 匹配 <h1>Hello, Sara</h1>。
Note: 组件命名以大写字母开头。
React 将小写开头的组件当做 DOM 标签处理。例如,
<div /> 表示一个 HTML div 标签, 但是
<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 的小组件开始, 渐渐扩展到最上层视图层级。
提取组件
不要害怕吧组件粉等更小的组件。
例如, 思考 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">
{formateDate(props.date)}
</div>
</div>
);
}
组件接受 author(对象), text(字符串)和 date(日期) 作为 props, 描绘一个 评论界面到社交网站上。
这个组件修改需要技巧因为所有嵌套很难复用独立的部分。我们从中提取一些组件出来。
第一步我们提取 Avatar:
function Avatar(props) {
return (
<img className="Avatar"
src={props.user.avatarUrl}
alt={props.user.name}
/>
);
}
Avatar 不需要知道它被渲染在一个 Comment中。这是为什么我们给它的 prop 取一个通用的名字: user 而不是 author.
我们建议为组件 props 命名从组件自身角度出发,而不是内容在哪里使用。
我们还可以简化 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">
{formateDate(props.date)}
</div>
</div>
);
}
接下来,我么提取一个 UserInfo 组件紧邻用户的名称来渲染 Avatar :
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">
{formateDate(props.date)}
</div>
</div>
);
}
提取组件看起来枯燥无味,但是一版可复用组件在一个较大的应用中回报丰厚。
好的标准是一部分你的 UI 被多次应用(Button, Panel, Avatar), 或者它足够复杂(App, FeedStory, Comment), 成为一个可复用的组件是个好的选择。
Props 是只读的
不论你以函数还是类的方式声明一个组件,它必须从不修改它的 props. 思考许下 sum 函数:
function sum(a, b) {
return a + b;
}
类似的函数被成为 “pure(纯)” ,因为他们不尝试修改他们的输入,而且他们根据相同的输入返回相同的输出。
相反, 下面这个函数就不是纯函数,因为它修改了自己的入参。
function withdraw(account, amount) {
account.total -= amount;
}
React 相当灵活但是它有一个严格的规则:
所有 React 组件必须想一个纯函数一样对待它们的 props.
当然, 应用 UI 随时间动态改变。下一部分,介绍一个新概念 “state”.
State 使得 React 组件可以在响应用户行为,网络请求或任何东西时随时间变化改变它们的输出,却不破坏这条规则。
最后
我有点分不清楚到底应该严格要求自己挤时间做,还是随意些。这个问题得好好思考一下。