组件定义

组件可以将UI切分成一些独立的、可复用的部件,这样你就只需专注于构建每一个单独的部件。
组件从概念上看就像是函数,它可以接收任意的输入值(称之为“props”),并返回一个需要在页面上展示的React元素。
react组件的定义有两种类型:
1.函数定义

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

该函数是一个有效的React组件,它接收一个单一的“props”对象并返回了一个React元素。我们之所以称这种类型的组件为函数定义组件,是因为从字面上来看,它就是一个JavaScript函数。
2.类组件
你也可以使用 ES6 class 来定义一个组件:

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

组件渲染

在前面,我们遇到的React元素都只是DOM标签:

  1. const element = <div />;

然而,React元素也可以是用户自定义的组件:

  1. const element = <Welcome name="Sara" />;

当React遇到的元素是用户自定义的组件,它会将JSX属性作为单个对象传递给该组件,这个对象称之为“props”。
例如传递给组件的时候是姜Welcome作为一个容器,
(1),包含属性key:name,value:’Sara’;key: age, value: 18
(2).Welcome组件定义的时候,会接收一个props对象例如:
const props={}
props.name =”Sara”
props.age =”18”
其实组件就相当于创建了一个函数,属性就是形参,组件定义就是函数定义,函数定义接守的时候采用的是使用一个对象总体接守传递的形参,实际在对象中进行具体属性派发
例如,这段代码会在页面上渲染出”Hello,Sara”:

  1. function Welcome(props) {
  2. return <h1>Hello, {props.name}</h1>;
  3. }
  4. const element = <Welcome name="Sara" />;
  5. ReactDOM.render(
  6. element,
  7. document.getElementById('root')
  8. );
  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>

    组合组件

    组件可以在它的输出中引用其它组件,这就可以让我们用同一组件来抽象出任意层次的细节。在React应用中,按钮、表单、对话框、整个屏幕的内容等,这些通常都被表示为组件。
    例如,我们可以创建一个App组件,用来多次渲染Welcome组件:
    1. function Welcome(props) {
    2. return <h1>Hello, {props.name}</h1>;
    3. }
    4. function App() {
    5. return (
    6. <div>
    7. <Welcome name="Sara" />
    8. <Welcome name="Cahal" />
    9. <Welcome name="Edite" />
    10. </div>
    11. );
    12. }
    13. ReactDOM.render(
    14. <App />,
    15. document.getElementById('root')
    16. );
    通常,一个新的React应用程序的顶部是一个App组件。但是,如果要将React集成到现有应用程序中,则可以从下而上使用像Button这样的小组件作为开始,并逐渐运用到视图层的顶部。

    警告: 组件的返回值只能有一个根元素。这也是我们要用一个<div>来包裹所有<Welcome />元素的原因。

提取组件

你可以将组件切分为更小的组件,这没什么好担心的。
例如,来看看这个Comment组件:

  1. function Comment(props) {
  2. return (
  3. <div className="Comment">
  4. <div className="UserInfo">
  5. <img className="Avatar"
  6. src={props.author.avatarUrl}
  7. alt={props.author.name}
  8. />
  9. <div className="UserInfo-name">
  10. {props.author.name}
  11. </div>
  12. </div>
  13. <div className="Comment-text">
  14. {props.text}
  15. </div>
  16. <div className="Comment-date">
  17. {formatDate(props.date)}
  18. </div>
  19. </div>
  20. );
  21. }

这个组件接收author(对象)、text(字符串)、以及date(Date对象)作为props,用来描述一个社交媒体网站上的评论。
这个组件由于嵌套,变得难以被修改,可复用的部分也难以被复用。所以让我们从这个组件中提取出一些小组件。
首先,我们来提取Avatar组件:
// 第一步提取:

  1. // 第一步提取:
  2. function Avatar(props) {
  3. // const props = {
  4. // user: {
  5. // avatarUrl:''
  6. // name:''
  7. // }
  8. // }
  9. return (
  10. <img className="Avatar"
  11. src={props.user.avatarUrl}
  12. alt={props.user.name}
  13. />
  14. );
  15. }

// 第二部提取

  1. function UserInfo (props){
  2. // props={
  3. // user:{
  4. // avatarUrl:'',
  5. // name:''
  6. // }
  7. // }
  8. return (
  9. <div className="UserInfo">
  10. <Avatar user={props.user} />
  11. <div className="UserInfo-name">
  12. {props.user.name}
  13. </div>
  14. </div>
  15. );
  16. }

// 简化后代码

  1. function Comment(props) {
  2. return (
  3. <div className="Comment">
  4. <UserInfo user={props.author} />
  5. <div className="Comment-text">
  6. {props.text}
  7. </div>
  8. <div className="Comment-date">
  9. {formatDate(props.date)}
  10. </div>
  11. </div>
  12. );
  13. }

提取组件一开始看起来像是一项单调乏味的工作,但是在大型应用中,构建可复用的组件完全是值得的。当你的UI中有一部分重复使用了好几次(比如,ButtonPanelAvatar),或者其自身就足够复杂(比如,AppFeedStoryComment),类似这些都是抽象成一个可复用组件的绝佳选择,这也是一个比较好的做法。

Props的只读性

无论是使用函数或是类来声明一个组件,它决不能修改它自己的props。来看这个sum函数:

  1. function sum(a, b) {
  2. return a + b;
  3. }

类似于上面的这种函数称为“纯函数”,它没有改变它自己的输入值,当传入的值相同时,总是会返回相同的结果。
与之相对的是非纯函数,它会改变它自身的输入值:

  1. function withdraw(account, amount) {
  2. account.total -= amount;
  3. }

React是非常灵活的,但它也有一个严格的规则:
所有的React组件必须像纯函数那样使用它们的props。
当然,应用的界面是随时间动态变化的,我们将在下一节介绍一种称为“state”的新概念,State可以在不违反上述规则的情况下,根据用户操作、网络响应、或者其他状态变化,使组件动态的响应并改变组件的输出。