Extendiendo React.componentes de js


Una de las cosas que más aprecio de Backbone.js es cómo funciona la herencia simple y elegante. Estoy empezando a familiarizarme con React, y realmente no puedo encontrar nada en react que se asemeje a este código troncal

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

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

En react tenemos mixins , y usando esos podríamos acercarnos un poco al ejemplo anterior si fuéramos así

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

Esto es menos repetitivo que definir las mismas cosas una y otra vez, pero no parece ser tan flexible como la forma de la columna vertebral. Por ejemplo, obtengo un error si intento redefinir / sobrescribir un método que existe en uno de mis mixins. Además de eso, la Reacción.js way es más código para escribir.

Hay algunas cosas increíblemente inteligentes en react, y se siente como que este es más el caso de mí no conseguir cómo hacer esto correctamente, de lo que se siente como una característica que falta en React.

Cualquier puntero es muy apreciado.

Author: Ahrengot, 2014-09-08

4 answers

Para obtener algo que se asemeja a la herencia (en realidad composición como se señala en los comentarios), puede hacer un Airplane en su ejemplo envolver sí mismo en un Vehicle. Si desea exponer métodos en Vehicle en el componente Airplane, puede usar un ref y conectarlos uno por uno. Esto no es exactamente herencia (en realidad es composición), particularmente porque el this.refs.vehicle no será accesible hasta después de que el componente haya sido montado.

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

También es vale la pena mencionar que en la documentación oficial de React prefieren la composición sobre la herencia:

Entonces, ¿Qué Pasa Con La Herencia? En Facebook, utilizamos React en miles de componentes, y no hemos encontrado ningún caso de uso en el que recomienda crear jerarquías de herencia de componentes.

Los accesorios y la composición le dan toda la flexibilidad que necesita para personaliza el aspecto y el comportamiento de un componente de forma explícita y segura. Recuerde que los componentes puede aceptar apoyos arbitrarios, incluyendo valores primitivos, elementos React o funciones.

Si desea reutilizar la funcionalidad que no es de interfaz de usuario entre los componentes, sugiera extraerlo en un módulo JavaScript separado. El los componentes pueden importarlo y usar esa función, objeto o clase, sin extenderlo.

Otra cosa que vale la pena mencionar es que usando ES2015 / ES6 + también puede extender los props de objeto desde el componente Airplane al componente Vehicle

render: function() {
    return (
        <Vehicle {...this.props}>
            <h1>J/K I'm an airplane</h1>
        </Vehicle>
    );
}
 56
Author: Ross Allen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-15 05:00:47

Mediante el apalancamiento ReactOO, puedes usar fácilmente la herencia (Descargo de responsabilidad : Soy el autor de 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>
introduzca la descripción de la imagen aquí
 3
Author: Jim Ma,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-27 13:43:16

Si usas el paquete webpack+babel+react NPM configurado en tu proyecto, entonces en la implementación de OOP de ES6 debería ser tan simple como esto:

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

Nota: Aquí hay un kit de inicio simple con tal configuración: https://github.com/alicoding/react-webpack-babel

 3
Author: Ashot,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-29 01:57:50

Creo que la extensión se puede hacer con el uso de jQuery.extend o similar

Base.jsx

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

Niño.jsx

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

module.exports = React.createClass($.extend({},Base,{
    methodB:function(){
        ...
        this.methodA();
        ...
    },
    render:function(){
        return ...
    }
}));
 -3
Author: pgregory,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-10 09:55:47