Skip to content

Latest commit

 

History

History
170 lines (137 loc) · 4.55 KB

【译】快速起步-组合与继承.md

File metadata and controls

170 lines (137 loc) · 4.55 KB
title date version
快速起步-组合与继承
2017-04-26 06:19:51 -0700
15.5.0

组合 VS. 继承

React 具有很强大的组合模型,我们推荐使用组合而不是继承来重用组件之间的代码。

在这一章节中,我们将思考一些React新手通常遇到的问题,并展示如何使用组合来解决它们。

容器

一些组件并不能提前知道它们的子集。这在通用盒子组件,如 Sidebar 或者 Dialog 上尤其常见。

我们推荐这类组件使用特定的 children 属性,将子元素传递到其输出中:

function FancyBorder(props) {
  return (
    <div className={'FancyBorder FancyBorder-' + props.color}>
      {props.children}
    </div>
  );
}

这允许其他组件通过嵌套JSX传递任意的子集到组件内部:

function WelcomeDialog() {
  return (
    <FancyBorder color="blue">
      <h1 className="Dialog-title">
        Welcome
      </h1>
      <p className="Dialog-message">
        Thank you for visiting our spacecraft!
      </p>
    </FancyBorder>
  );
}

Try it on CodePen.

任何JSX标签 <FancyBorder> 内部的内容,都会作为 children 属性传递给 FancyBorder 组件。由于 FancyBorder 会在 <div> 中渲染 {props.children},传递的元素将会出现在最终输出中。

虽然这不太常见,但有时您可能需要在组件中设置多个“孔”(holes,译者注:插槽)。在这种情况下,您可以采用您自己的约定,而不是使用 children

function SplitPane(props) {
  return (
    <div className="SplitPane">
      <div className="SplitPane-left">
        {props.left}
      </div>
      <div className="SplitPane-right">
        {props.right}
      </div>
    </div>
  );
}

function App() {
  return (
    <SplitPane
      left={
        <Contacts />
      }
      right={
        <Chat />
      } />
  );
}

Try it on CodePen.

<Contacts /><Chat /> 这样的React元素只是对象,所以你可以像传递其他数据一样将其作为属性传递。

具象化

有时我们认为某些组件是其他组件的“特殊情况”。比如,我们认为 WelcomeDialog 是一个特殊的 Dialog

在React中,这也可以通过组合来实现,其中更“特殊”的组件会渲染更“通用”的组件,并且使用属性来配置通用组件:

function Dialog(props) {
  return (
    <FancyBorder color="blue">
      <h1 className="Dialog-title">
        {props.title}
      </h1>
      <p className="Dialog-message">
        {props.message}
      </p>
    </FancyBorder>
  );
}

function WelcomeDialog() {
  return (
    <Dialog
      title="Welcome"
      message="Thank you for visiting our spacecraft!" />
  );
}

Try it on CodePen.

组合对应定义为类的组件同样适用:

function Dialog(props) {
  return (
    <FancyBorder color="blue">
      <h1 className="Dialog-title">
        {props.title}
      </h1>
      <p className="Dialog-message">
        {props.message}
      </p>
      {props.children}
    </FancyBorder>
  );
}

class SignUpDialog extends React.Component {
  constructor(props) {
    super(props);
    this.handleChange = this.handleChange.bind(this);
    this.handleSignUp = this.handleSignUp.bind(this);
    this.state = {login: ''};
  }

  render() {
    return (
      <Dialog title="Mars Exploration Program"
              message="How should we refer to you?">
        <input value={this.state.login}
               onChange={this.handleChange} />
        <button onClick={this.handleSignUp}>
          Sign Me Up!
        </button>
      </Dialog>
    );
  }

  handleChange(e) {
    this.setState({login: e.target.value});
  }

  handleSignUp() {
    alert(`Welcome aboard, ${this.state.login}!`);
  }
}

Try it on CodePen.

那么继承呢?

在Facebook,我们在数以千计的组件中使用React,并且我们没有发现任何用例会要求我们创建组件继承层次结构。

当你需要用安全的方式定制组件的外观和形式时,属性和组合给了你所有的灵活性。 请记住,组件接受任意props,包括原始值、React元素或函数。

如果你想在组件之中重用非UI的功能,我们建议您将其提取到单独的 JavaScript 模块中。组件可以导入它,并在不扩展它的情况下,使用哪些函数,对象或者是类。