您好, 欢迎来到 !    登录 | 注册 | | 设为首页 | 收藏本站

React 组合组件

React 组合组件

使用组件的目的就是通过构建模块化的组件,相互组合组件最后组装成复杂的应用。

在 React 组件中要包含其他组件作为子组件,只需要把组件当作 DOM 元素引入就可以了。

例子:头像的组件 Avatar 包含两个子组件 ProfilePic 头像和 ProfileLink:

import React from 'react';
import { render } from 'react-dom';

const ProfilePic = (props) => {
  return (
    <img src={'http://graph.facebook.com/' + props.username + '/picture'} />
  );
}

const ProfileLink = (props) => {
  return (
    <a href={'http://www.facebook.com/' + props.username}>
      {props.username}
    </a>
  );
}

const Avatar = (props) => {
  return (
    <div>
      <ProfilePic username={props.username} />
      <ProfileLink username={props.username} />
    </div>
  );
}

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

通过 props 。

循环插入子元素

如果组件中包含通过循环插入的子元素,为了保证重新渲染 UI 的时候能够正确这些子元素,每个元素都需要通过特殊的 key 指定唯一值。具体原因见,为了内部 diff 的效率。

key 必须直接在循环中设置:

const ListItemWrapper = (props) => <li>{props.data.text}</li>;

const MyComponent = (props) => {
  return (
    <ul>
      {props.results.map((result) => {
        return <ListItemWrapper key={result.id} data={result}/>;
      })}
    </ul>
  );
}

你也可以用 key 值作为,子元素作为值的对象字面量来子元素列表,虽然这种的场景有限,参见,但是种情况下要注意的子元素重新渲染后在 DOM 中的顺序问题。

实际上浏览器在遍历字面量对象的时候会保持顺序一致,除非存在值可以被转换成整数值,这种值会排序并放在其他之前被遍历到,所以为了防止这种情况发生,可以在构建这个字面量的时候在key 值前面加字符串前缀,比如:

render() {
  var items = {};

  this.props.results.forEach((result) => {
    // If result.id can look like a number (consider short hashes), then
    // object iteration order is not guaranteed. In this case, we add a prefix
    // to ensure the keys are strings.
    items['result-' + result.id] = <li>{result.text}</li>;
  });

  return (
    <ol>
      {items}
    </ol>
   );
}

this.props.children

组件里面包含的子元素会通过 props.children 传递进来。

比如:

React.render(<Parent><Child /></Parent>, document.body);
React.render(<Parent><span>hello</span>{'world'}</Parent>, document.body);

HTML 元素会作为 React 组件对象、JS 表达式结果是节点,都会存入 Parent 组件的 props.children。

一般来说,可以直接将这个作为父组件的子元素 render:

const Parent = (props) => <div>{props.children}</div>;

props.children 通常是组件对象的数组,但是当只有子元素的时候,props.children 将是这个唯一的子元素,而不是数组了。

 提供了额外的方便操作这个。

组件

将组件拆分为更小的组件。

例如,参考如下 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(日期)作为 props。

该组件由于嵌套的关系,变得难以维护,且很难复用它的各个部分。因此,让我们从中一些组件出来。

首先,我们将 Avatar 组件:

function Avatar(props) {
  return (
    <img className="Avatar"
      src={props.user.avatarUrl}
      alt={props.user.name}
    />

  );
}

Avatar 不需知道它在 Comment 组件内部是如何渲染的。因此,我们给它的 props 起了更通用的名字: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">
        {formatDate(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">
        {formatDate(props.date)}
      </div>
    </div>
  );
}

最初看上去,组件可能是一件繁重的工作,但是,在大型应用中,构建可复用组件库是完全值得的。根据经验来看,如果 UI 中有一部分被多次使用(Button,Panel,Avatar),或者组件本身就足够复杂(App,Story,Comment),那么它就是可复用组件的候选项。


联系我
置顶