React 组件间的复合


JSX赋予了React组件强大的表现能力,它允许我们使用类似HTML的语法来创建自定义元素和组件。结合小巧、简单的组件和数据对象,可以构造出庞大而复杂的组件,这就是组件复合


  1. 组件的组合与从属关系
  2. 组件的子级


1. 组件的组合与从属关系

1.1 组件的组合

我们要实现一个显示用户头像和用户名的组件,其结构如下:

<div>
  <img src="……" />
  <a href="……">userName</a>
</div>

React组件应该通过开发简单的组件,以达到分离程序关注面的目的,并通过组合这些简单的组件最终组成复杂的组件。以上结构,我们可以按以下形式开发并组合组件:

var Avatar = React.createClass({
  render: function() {
    return (
      <div>
        <ProfilePic username={this.props.username} />
        <ProfileLink username={this.props.username} />
      </div>
    );
  }
});

var ProfilePic = React.createClass({
  render: function() {
    return (
      <img src={'http://niefengjun.cn/' + this.props.username + '/picture'} />
    );
  }
});

var ProfileLink = React.createClass({
  render: function() {
    return (
      <a href={'http://niefengjun.cn/' + this.props.username}>
        {this.props.username}
      </a>
    );
  }
});

ReactDOM.render(
  <Avatar username="nodejs" />,
  document.getElementById('example')
);


1.2 组件从属关系

在上面示例中,Avatar组件是ProfilePicProfileLink实例的拥有者(即:在render()中创建了所拥有的组件)。

React组件从属关系不同于父子关系,从属关系是React组件所特有的,父子组件类似于DOM中的元素关系。如:Avatar组件拥有divProfilePicProfileLink实例,而divProfilePicProfileLink父级,但不是拥有者。


2. 组件的子级

2.1 子级

我们可以实例化 React 组件时添加子级,添加子级可以在开始标签和结束标签之间引用 React 组件或 Javascript 表达式引用,其语法结构如下:

<Parent><Child /></Parent>

父组件中,可以通过this.props.children属性读取子组件,子组件是一个通过React.Children工具类来操作的,不透明的数据结构。


2.2 动态子级

有些时候组件子级数量是不确定的,因此我们需要跟据父组件数据来动态生成子级,生成子级时一般需要向子级传递数据。

如,动态生成一个如下结构的网站菜单:

<ul>
  <li><a href="http://www.niefengjun.cn/nodejs">Node.js</a></li>
  <li><a href="http://www.niefengjun.cn/javascript">JavaScript</a></li>
  ……
</ul>

实现如下:

var ListItemWrapper = React.createClass({
  render: function() {
    return <li><a href="{this.props.data.url}">{this.props.data.text}</a></li>;
  }
});

var Menu = React.createClass({
  render: function() {
    return (
      <ul>
        {this.props.menus.map(function(result) {
           return <ListItemWrapper key={result.id} data={result} />;
        })}
      </ul>
    );
  }
});

var menus = [{id: 1, url:'http://niefengjun.cn/nodejs', text:'Node.js'},
  {id: 2, url:'http://niefengjun.cn/javascript', text:'JavaScript'},
  {id: 3, url:'http://niefengjun.cn/db', text:'数据库'}
]
ReactDOM.render(
  <Menu menus={menus} />,
  document.getElementById('example')
);