扩展React.js组件

时间:2014-09-08 08:59:07

标签: javascript inheritance backbone.js reactjs

我最欣赏Backbone.js的一件事是简单优雅的继承是如何工作的。我开始接触React,并且无法找到类似于Backbone代码的任何反应

var Vehicle = Backbone.View.extend({
    methodA: function() { // ... }
    methodB: function() { // ... }
    methodC: function() { // ... }
});

var Airplane = Vehicle.extend({
    methodC: function() {
        // Overwrite methodC from super
    }
});

在做出反应我们have mixins,并使用那些我们可以得到一些接近上面的例子,如果我们这样做

var vehicleMethods = {
    methodA: function() { // ... }
    methodB: function() { // ... }
}

var Vehicle = React.createClass({
    mixins: [vehicleMethods]
    methodC: function() { 
        // Define method C for vehicle
    }
});

var Airplane = React.createClass({
    mixins: [vehicleMethods]
    methodC: function() {
        // Define method C again for airplane
    }
});

这比重复定义相同内容的重复性要小,但它似乎没有Backbone方式那么灵活。例如,如果我尝试重新定义/覆盖我的一个mixin中存在的方法,则会出错。最重要的是,React.js方式是我编写的更多代码。

有一些令人难以置信的聪明的东西反应,感觉就像我没有得到如何正确地做到这一点,而不是感觉像React缺少一个功能。

非常感谢任何指针。

4 个答案:

答案 0 :(得分:59)

要获得类似于继承的内容(实际上 composition ,如注释中所指出的那样),您可以在示例中将Airplane包裹在Vehicle中。如果您想在Vehicle组件的Airplane上公开方法,可以使用ref并逐个连接它们。这不完全是继承(它实际上是组合),特别是因为在安装组件之后才能访问this.refs.vehicle

var Vehicle = React.createClass({
    ...
});

var Airplane = React.createClass({
    methodA: function() {
      if (this.refs != null) return this.refs.vehicle.methodA();
    },
    ...
    render: function() {
        return (
            <Vehicle ref="vehicle">
                <h1>J/K I'm an airplane</h1>
            </Vehicle>
        );
    }
});

另外值得一提的是,React official documentation他们更喜欢构图而不是继承:

  

那么继承怎么样?在Facebook,我们使用React成千上万   组件,我们还没有找到任何用例   建议创建组件继承层次结构。

     

道具和作曲为您提供所需的所有灵活性   以明确和安全的方式定制组件的外观和行为。   请记住,组件可以接受任意道具,包括   原始值,React元素或函数。

     

如果您想在组件之间重用非UI功能,我们   建议将其解压缩到一个单独的JavaScript模块中。该   组件可以导入它并使用该函数,对象或类,   没有扩展它。

另外值得一提的是,使用ES2015 / ES6 +还可以将对象道具从Airplane组件传播到Vehicle组件

render: function() {
    return (
        <Vehicle {...this.props}>
            <h1>J/K I'm an airplane</h1>
        </Vehicle>
    );
}

答案 1 :(得分:4)

如果您在项目中使用webpack + babel + react NPM软件包,那么在ES6 OOP实现中,它应该像这样简单:

import React, { Component } from 'react';
import ReactDOM from 'react-dom';

class BaseComponentClass extends Component {
  componentDidMount() {} 
  render() { return (<div>Base Component</div>) }
}
class InheritedComponentClass extends BaseComponentClass {
  // componentDidMount is inherited
  render() { return (<div>Inherited Component</div>) } // render is overridden 
}
ReactDOM.render(<InheritedComponentClass></InheritedComponentClass>, 
     document.getElementById('InheritedComponentClassHolder'));

注意:这是一个简单的入门套件,具有这样的设置:https://github.com/alicoding/react-webpack-babel

答案 2 :(得分:3)

通过利用ReactOO,您可以轻松使用继承(免责声明:我是 ReactOO 的作者):

(function () {

    // Class definitions. ReactOO requires class definition first just like you did in an OO way.

    window.Vehicle = window.ReactOO.ReactBase.extend({
        getReactDisplayName: function () {
            return 'Vehicle';
        },

        onReactRender: function (reactInstance) {
            var self = this;

            var text = self.methodC();

            return React.createElement('div', {}, text);
        },

        methodA: function () {
            console.log('Vehicle method A');
        },

        methodB: function () {
            console.log('Vehicle method B');
        },

        methodC: function () {
            return 'Vehicle method C';
        }
    });

    window.Airplane = window.Vehicle.extend({
        getReactDisplayName: function () {
            return 'Airplane';
        },

        methodC: function () {
            // Call this._super() to execute parent method.
            //this._super();
            return 'Airplane method C';
        }
    });

    var vehicle = new window.Vehicle();
    vehicle.render({}, '#vehicle');

    var airPlane = new window.Airplane();
    airPlane.render({}, '#airPlane');
})();
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>ReactOO Vehicle-Aireplane Example</title>
    <link rel="stylesheet" href="css/base.css" />
    <script src="scripts/react.js"></script>
    <script src="scripts/react-dom.js"></script>
    <script src="../src/reactoo.js"></script>
</head>
<body>
    <div id="vehicle">
    </div>
    <div id="airPlane">
    </div>
    <script src="scripts/vehicleAirplane.js">
    </script>
</body>
</html>
enter image description here

答案 3 :(得分:-4)

我认为可以使用jQuery.extend或类似的

进行扩展

<强> Base.jsx

module.exports = {
    methodA:function(){
        ...
    }
}

<强> Child.jsx

var Base = require('./Base.jsx');

module.exports = React.createClass($.extend({},Base,{
    methodB:function(){
        ...
        this.methodA();
        ...
    },
    render:function(){
        return ...
    }
}));