快速开始React

组合还是继承?

2017-04-29  本文已影响92人  莫铭

React具有强大的组合模型,我们推荐使用组合来代替继承,这样可以在组件间重用代码。
在本节中,我们将考虑几个问题,遇到这些问题时,刚接触React的开发者一般会考虑使用继承,而我们将展示如何用组合来解决他们。

包含

一些组件提前不知道它的孩子。在诸如侧栏和对话框这些通用“框”中尤为常见。
我们建议这种组件使用专门的childrenprop来直接传递子元素到他们的输出:

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>
  );
}

在CodePen上试一试
<FancyBorder>JSX标签中的所有东西都会作为childrenprop传递给FancyBorder组件。FancyBorder<div>中渲染{props.children},因此传入的元素将出现在最终输出中。
虽然这比较少见,但有时你还是会需要在组件中放置多个“槽位”。在这种情况下,你可以使用自己习惯来,来代替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 />
      } />
  );
}

在CodePen上试一试
诸如<Contacts /><Chat />的React元素也是对象,所以你可以像其他数据一样作为props传递。

特殊化

有时你我们认为一些组件是其他组件的“特殊情况”。比如,我们说WelcomeDialogDialog的特例。
在React中,这也可以通过组合来完成:通过props配置一个相对“通用的”组件,来渲染出一个相对“特殊的”组件:

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!" />
  );
}

在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}!`);
  }
}

在CodePen上试一试

那继承咋样?

在Facebook,我们在数千个组件中使用React,尚未发现有什么组件,需要我们推荐你使用继承去实现。
Props和组合提供了足够的灵活度,使得你能够以明确且安全的方法来自定义组件的外观和行为。
如果你想在组件间复用非界面功能,我们建议将它抽取到单独的JavaScript模块。组件可以导入它,然后使用需要的函数,对象或类,而不必扩展(继承)它。

上一篇 下一篇

猜你喜欢

热点阅读