React 起手 - 组合 vs 继承

2,149 阅读4分钟
原文链接: varnull.cn

当然,React也是提倡组合优于继承的,这里对一些新手来说,往往他们喜欢用继承,我们来看一下如果用组合来更好的来解决问题吧~

这里的这个例子所实现的功能,当时用vue1实现的时候特别困难,如今vue2应该也支持了相应的功能,不过当我看到入门文章的这里的时候,我感觉这是React很强大的地方,简单来说就是,可以进行依赖注入,注入什么呢?当然什么都可以,这就给UI组件强大的灵活能力,即父组件只用实现那些不变的部分,那些变化的部分我只需要抽取出来行程单独的子组件,这样父组件在不知道他内部某些部分是什么样子的时候就可以进行抽象。

还是先看例子来理解一下:

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

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

这个例子中FancyBorder组件中的不变部分是一个加了样式的div容器,变化的内容就是这个容器中的内容,这个内容应该由使用的用户来决定是什么,这样就可以组合出各种各样的Dialog,例如上面所示的WelcomeDialog,这里注意的就是props.children这个是被自动注入连接起来的,来表示组件的子内容。

然而大多数情况你可能需要更细粒度的子内容划分,其实这个概念有点像vue中的插槽slot,只不过这个东西还是可以挂在props上的,可以看出React中的props很强大,props既可以是原始数据类型,也可以是对象,当然也可以是jsx中的element(这其实也是个对象),如下例子:

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

如上,两个插槽,一个是props.left, 一个是props.right,分别对应两个React 元素,Contacts/> Chat/>。看到这里我想起很多人吐槽jsx,我也是刚开始看jsx到这里,我觉得它可能对于设计感的纯html的模式有些颠覆,让设计书写样式时有些割裂感,但是不能否定的是我还是感觉到他的强大的,怎么说的,就是这样一种感觉,我写的是html的外衣,但是我写的心是包装好的对象,这意味着你对html有了绝对编程上的控制,这种思想我觉得是我今后在实际开发中还需要慢慢去体会的。下面的例子就是一个通用dialog的实现,我反正第一眼看上去觉得还是挺优雅的啊,轻微觉得比vue的slot感觉干净一些,作用域也更清晰可以自解释:

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

说了这么多,最后呢?如果我非要在React中用组件继承呢?官网是这样说的,在Facebook我们用React写了成千上万的组件,我们还没有发现我们有使用继承来实现组件的情况。

props和组合给了组件强大的生命力,我们需要用一种显示的方式来自定义组件的行为和样子。记住,组件可以接受任意的props,包括原始数据类型,React elements 或者functions

另外,如果你想重用一些组件中公用的非展示类的方法,我们建议把它抽取出来作为一个单独的Javascript module.在组件需要它的时候进入进来就好啦,不需要继承。其实像不像就是mixin,混入,或者貌似是php中的Trait?很多时候我们会发现,思想都是共通的,然而我还是需要多踩坑多思考才能体会和领悟到别人口中的最佳实践不是么?!

哈哈,让踩坑的暴风雨来的更猛烈些吧!!!

如果我的文章对您有帮助
欢迎打赏(。・ω・)