继承和组合中的道具

Props in inheritance and composition

我有一个名为 Panel 的 React class,我想将其用作 UI 中各种特定面板的可重用组件。每个面板都有一个共同的标题栏和一个 "Submit" 按钮,但每种面板的 body 是唯一的。

我可以使用继承 (sub-classing) 或组合来实现此目的,但在这种情况下哪个最好?

我已经尝试 sub-classing,在 parent Panel 中使用渲染方法,然后让 child 面板覆盖 renderBody 方法,render 使用。这似乎崩溃了,因为每个特定的面板都需要自己的道具(例如 "title"),并且当修改后的道具被传递给组件构造函数中的 super 时,React 会抱怨(错误消息是,"When calling super() . . . make sure to pass up the same props that your component's constructor was passed.").由于 "title" 特定于一种面板,我不希望最终消费者必须自己指定 "title" 道具。

class Panel extends React.Component {

  render() {
    return (
      <div>
        <div>{this.props.title}</div>
        <div>{this.renderBody()}</div>
        <div><button>Submit</button></div>
      </div>
    )
  }

}

class SomeSubPanel extends Panel {

  constructor(props) {
    // React throws the error message at the following line
    let newProps = Object.assign({}, props, {title: "Some Sub Panel"})
    super(newProps)
  }

  renderBody() {
    return (<div>Panel Body Goes Here</div>)
  }

}

使用组合似乎不像 sub-classing 那样整洁,因为每个面板只需要有一个特定的 body,但是 body(即 HTML) 不能在组件之间传递。

拥有 child 可以将特征传递给可重用 parent 组件的组件会是什么 "React way"?

非常感谢!

一定要用构图。一般来说,我认为你不应该扩展你自己的 React 组件。实现方法如下:

class ReusablePanel extends React.Component {
  render () {
    return (
      <div>
        <div>{this.props.title}</div>
        <button onClick={this.props.onSubmit}>Submit</button>
        {this.props.children}
      </div>
    )
  }
}

class FootballPanel extends React.Component {
  handleSubmitButtonClick = () => {
    // do something
  }

  render () {
    return (
      <ReusablePanel title='Football' onSubmit={this.handleSubmitButtonClick}>
        <div>{/* Football markup */}</div>
      </ReusablePanel>
    )
  }
}

class ArsenalPanel extends React.Component {
  handleSubmitButtonClick = () => {
    // do something
  }

  render () {
    return (
      <ReusablePanel title='Arsenal' onSubmit={this.handleSubmitButtonClick}>
        <div>{/* Arsenal markup */}</div>
      </ReusablePanel>
    )
  }
}

我认为 React 的做法很简单:

// using a function for brevity, but could be a class
let Panel = ({ title, handleSubmit, children }) =>
  <div>
    <h1>{title}</h1>
    {children}
    <button onClick={handleSubmit}>Submit</button>
  </div>

然后在别处:

<Panel title="Foo" handleSubmit={onSubmit}>{specificChildContent}</Panel>