【问题标题】:React components as plain JS objects?将组件反应为普通的 JS 对象?
【发布时间】:2015-06-23 08:55:07
【问题描述】:

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

也许您有一些工厂功能或类似功能的示例可以分享?

谢谢!

【问题讨论】:

  • React.Component 是一个普通的 javascript 函数,因为 es6 只是语法糖 - 签名是 function ReactComponent(props, context)
  • 这里有点不清楚你的意思。您是指代码通过 jsx 和 es6 转译器后的 javascript 最终结果吗?

标签: javascript class reactjs javascript-objects ecmascript-6


【解决方案1】:

React.Component 是一个普通的 javascript 函数,因为 es6 类是围绕它们的语法糖。所以我们可以使用我们喜欢的任何类似 es5 类的概念,例如我只是在这里借用了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 继承”,您应该能够应用这些解决方案中的任何一个。

【讨论】:

  • 谢谢,知道React.Component(props, context)签名很有用。我还在寻找一种方法来使用 render({ props, state }, setState) 之类的参数更新 render 方法,以便摆脱组件中任何地方的烦人 this
【解决方案2】:

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

一个简单的例子:

第一步:安装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> 
  )
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-06-07
    • 1970-01-01
    • 2016-08-30
    • 2022-09-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多