Components 将UI拆分成独立可复用的零件,可以单独考虑每个零件。
概述,components就像JavaScript的函数。他们接受武断的输入(called "props")和返回描述应该出现在屏幕上内容的元素。
函数和类组件
Functional and Class Components
定义一个组件最简单的方法是写一个JavaScript函数:
function Welcome(props){
return <h1>Hello,{props.name}</h1>;
}
这个函数是一个有效的React component 因为它接收一个带数据的“props”对象参数并返回一个React元素。因为他们字面上是JavaScript函数,我们叫这些组件为"functional"
你也可以使用一个ES6 类来定义一个组件:
class Welcome extends React.Component{
render(){
return <h1>Hello,{this.pops.name}</h1>;
}
}
以上两个组件从React的观点来看是等价的。
在接下来的几个小节中我们将讨论类增加的几个特性。目前,我们将先使用函数组件保证简洁。
渲染一个组件
以前,我们只鼓励表示DOM标签的React元素:
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')
);
在CodePen上试试吧
让我们着重说明下在例子中发生了什么:
1.我们用<Welcome name="Sara" />元素来调用ReactDOM.render();
2.React 用{name:'Sara'}作为props来调用Welcome组件;
3.我们的Welcome组件返回<h1>Hello,Sara</h1>元素作为结果;
4.React DOM 有效更新DOM适用<h1>Hello,Sara</h1>;
警告:
一般以首字母大写命名组件。
例如,<div />表示一个DOM标签,但是<Welcome />表示一个组件和要求Welcome在环境中。
组成组件
组件可以在他们的输出中提及其他组件。这让我们从不同的具体实现中提取出相同的组件抽象。一个按钮,一个表单,一个对话,一个屏幕:在React apps,所有的那些都被表达为组件。
例如,我们创建一个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')
);
在CodePen上试试吧
代表性地,新的React apps在最顶层有一个App组件。然而如果你集成React到一个已经存在的App中,你可能要从一个像按钮一样的小组件自下而上开始,逐渐在页面层级的最高处运行你的方法。
警告:
组件必须返回一个root元素,这是因为我们增加一个<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>
);
}
在CodePen上试试吧。
它接受一个author(对象),text(字符串),日期(时间)属性在社交媒体网站描述评论。
这个组件对于改变是机警的因为全耦合,它也难以复用其中的个体部分。让我们从中提取几个组件。
首先我们提取Avatar:
function Avatar(props){
return (
<img className="Avatar" src={props.user.avatarUrl} alt={props.user.name} />
);
}
Avatar不需要知道它将被渲染到Comment中。所以我们将给它的属性一个一般的名字:user而不是author。
我们建议从组件本身的角度去命名属性,而不是它将被使用的上下文。
我们现在简化组件一丁点:
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.author.name}</div>
<div className="Comment-date">{formatDate(props.date)}</div>
</div>
);
}
接下来,我们将提取一个UserInfo组件,Avatar紧挨着user`s name:
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>
);
}
在CodePen中试试吧。
起初提取组件似乎看起来像grunt 重组代码,但在大型app中复用组件可以成功调节。一个好的做法是如果你的UI的一部分被多次使用(Button,Panel,Avatar),或者足够复杂,复用组件是一个很好的选择。
属性是只读的
无论你是以一个函数或者是一个类的形式声明一个组件,都决不能修改它的属性。思考sum函数:
function sum(a,b){
return a+b;
}
像这样的函数被称为纯函数,因为它们不视图修改它们的输入,总是返回和输入一样的结果。
与此相反,这个函数不是纯函数,因为它改变自己的输入:
function withdraw(account,amount){
account.total-=amount;
}
React 是相当灵活的,但是它有一个严格的规则:
All React components must act like pure functions with respect to their props.
所有React组件必须向纯函数一样尊重它们的属性。
当然,应用UI是动态的,随时间变化的。在下一节,我们将介绍"state"新概念。在这个规律下,State允许React组件因户行为响应,网络响应,其他任何的随时改变它们的输出。