将组件作为普通 JS 对象进行反应?

React components as plain JS objects?

有没有人有使用 React 组件作为普通 JS 对象的经验,而不是烦人的 ES6 类 和弃用的 .createClass 方法。

也许你有一些工厂函数或类似的例子可以分享?

谢谢!

React.Component 是一个普通的 javascript 函数,因为 es6 classes 是围绕它们的语法糖。所以我们可以使用我们喜欢的任何类似 es5 class 的概念,例如我只是在这里借用了Backbone的extend方法:

// From backbone
var extend = function(protoProps) {
    var parent = this;
    var child;

    var extendObj = function(obj1, obj2) {
       for (var i in obj1) {
          if (obj1.hasOwnProperty(i)) {
             obj2[i] = obj1[i];
          }
       }
    };

    // The constructor function for the new subclass is either defined by you
    // (the "constructor" property in your `extend` definition), or defaulted
    // by us to simply call the parent constructor.
    if (protoProps && hasOwnProperty.call(protoProps, 'constructor')) {
      child = protoProps.constructor;
    } else {
      child = function() { return parent.apply(this, arguments); };
    }

    // Set the prototype chain to inherit from `parent`, without calling
    // `parent` constructor function.
    var Surrogate = function(){ this.constructor = child; };
    Surrogate.prototype = parent.prototype;
    child.prototype = new Surrogate;

    // Add prototype properties (instance properties) to the subclass,
    // if supplied.
    if (protoProps) extendObj(child.prototype, protoProps);

    // Set a convenience property in case the parent's prototype is needed
    // later.
    child.__super__ = parent.prototype;

    return child;
};

React.Component.extend = extend;

然后我们可以创建这样的组件:

var MyComponent = React.Component.extend({
    constructor: function() {
        console.log('hello from react component');

        this.state = {
            open: false
        };

        React.Component.apply(this, arguments);
    }
});

new MyComponent();

这只是一个示例(未经测试),您可以执行任何类型的原型实现,因为它只是一个普通函数。如果您搜索 "es5 inheritance",您应该能够应用任何这些解决方案。

我想我的回答晚了。但是我确实使用基于 javascript 对象的传统原型制作了很多 React 组件。如果你喜欢基于原型的对象,你可以尝试以下方法:)

一个简单的例子:

第 1 步:安装 inherits 模块

npm install inherits -S

然后,

const React = require('react'); // switch to import, if you like
const is = require('prop-types');
const inherits = require('inherits');

inherits(MyComponent, React.Component);
module.exports = MyComponent;
var prototype = MyComponent.prototype;

MyComponent.defaultProps = {
  onClick: function(){ }
};

MyComponent.propTypes = {
  onClick: is.func,
  href: is.string,
  label: is.string
}

function MyComponent(props) {
  React.Component.call(this, props);
  this.state = {clicked: false};
}

prototype.render = function() {
  return (
    <a href={this.props.href} onClick={this.props.onClick}>
      {this.props.label}
    </a>)
}

// for debugging purpose, set NODE_ENV production, will remove the following
if (process.env.NODE_ENV !== 'production') {
  MyComponent.displayName = 'MyComponent';
}

分离关注点的更高级方法是将方法放在不同的文件中。 (通常,受保护或私有方法,几个月或几年后您不需要知道这些。)然后,将它们合并到原型对象上。您可以通过以下方式完成。

...
const _proto = require('./prototype'); //make a prototype folder, and merge all files' methods into one.

...
var prototype = Object.assign(MyComponent.prototype, _proto);

或者,你想让你的组件成为一个 EventEmitter,你可以像下面那样做:

....
const _proto = require('./prototype');
const Emitter = require('component-emitter');

....
var prototype = Object.assign(MyComponent.prototype, _proto, Emitter.prototype);

function MyComponent(props) {
  React.Component.call(this, props);

  this.onClick = _=> this.emit("click");
}

prototype.render = function() {
  return <a href={this.props.href} onClick={this.onClick}>{this.props.label}</a>
}

在prototype文件夹中,可以这样写:

index.js

Object.assign(exports, require('./styles.js').prototype)

styles.js

const prototype = exports.prototype = {};

prototype.prepareStyles = function() {

  var styles = Object.defineProperties({}, {
    wrapper: { get: _=> ({
      backgroundColor: '#333'
    })},

    inner: {get: _=> {
       return this.state.clicked ? {...} : {...}
    }}
  });

  Object.defineProperties(this, {
    styles: {get: _=> styles}
  })
}
//All the methods are prefixed by prototype, so it is easy to cut and paste the methods around different files, when you want to hide some methods or move some methods to be with the constructor to make your component more easy to read.

然后,在主文件中。只需调用方法来准备所有样式:

function MyComponent(props) {
  React.Component.call(this, props);

  this.prepareStyles();
}

并使用样式,

prototype.render = function() {
  return ( 
      <div style={this.styles.wrapper}>
        <div styles={this.styles.inner}>hello world</div>
      </div> 
  )
}