UNPKG

@mjackson/my-react

Version:

A lightweight, drop-in replacement for React that avoids using ES6 classes and "this"

224 lines (181 loc) 5.99 kB
import React from 'react'; /** * Copyright 2013-2015, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ /** * Use invariant() to assert state which your program assumes to be true. * * Provide sprintf-style format (only %s is supported) and arguments * to provide information about what broke and what you were * expecting. * * The invariant message will be stripped in production, but the invariant * will remain to ensure logic does not differ in production. */ var NODE_ENV = undefined; var invariant = function(condition, format, a, b, c, d, e, f) { if (NODE_ENV !== 'production') { if (format === undefined) { throw new Error('invariant requires an error message argument'); } } if (!condition) { var error; if (format === undefined) { error = new Error( 'Minified exception occurred; use the non-minified dev environment ' + 'for the full error message and additional helpful warnings.' ); } else { var args = [a, b, c, d, e, f]; var argIndex = 0; error = new Error( format.replace(/%s/g, function() { return args[argIndex++]; }) ); error.name = 'Invariant Violation'; } error.framesToPop = 1; // we don't care about invariant's own frame throw error; } }; var invariant_1 = invariant; /** * React class properties we support. */ var ReactStatics = { displayName: true, defaultProps: true, propTypes: true, contextTypes: true, childContextTypes: true /** * React lifecycle methods we support. */ };var ReactLifecycle = { getChildContext: true, componentWillMount: true, componentDidMount: true, shouldComponentUpdate: true, componentWillUpdate: true, componentDidUpdate: true, componentWillUnmount: true /** * Custom lifecycle methods. */ };var MyLifecycle = { setupComponent: true, getElement: true, getNextState: true }; function isFunction(obj) { return typeof obj === "function"; } /** * Creates a new myReact component. The argument is the "component definition" * object and must contain at least the following property: * * - getElement(my) * * The component definition may also contain any of the following properties: * * - displayName * - defaultProps * - propTypes * - contextTypes * - childContextTypes * - getChildContext(my) * - setupComponent(my) * - componentWillMount(my) * - componentDidMount(my) * - getNextState(my, nextProps) * - shouldComponentUpdate(my, nextProps, nextState) * - componentWillUpdate(my, nextProps, nextState) * - componentDidUpdate(my, prevProps, prevState) * - componentWillUnmount(my) * * Additionally, the component definition may just be a function (instead of an * object), in which case that function will be used as the `getElement` value. */ function createComponent(def) { invariant_1(def, "createComponent is missing the component definition"); // Support plain functions as well as objects. var getElement = def.getElement || def; invariant_1(getElement, "getElement is missing from the component definition"); invariant_1(isFunction(getElement), "getElement must be a function"); var setupComponent = def.setupComponent; invariant_1(!setupComponent || isFunction(setupComponent), "setupComponent must be a function"); function Component(props) { React.Component.call(this, props); // Auto-bind instance methods. Object.keys(instanceMethods).forEach(function (key) { this[key] = instanceMethods[key].bind(undefined, this); }, this); if (setupComponent) setupComponent(this); } var proto = Component.prototype; Object.setPrototypeOf(proto, React.Component.prototype); proto.render = function () { return getElement(this); }; var getNextState = def.getNextState; if (getNextState) { invariant_1(isFunction(getNextState), "getNextState must be a function"); proto.componentWillReceiveProps = function (nextProps) { var nextState = getNextState(this, nextProps); if (nextState) this.setState(nextState); }; } var instanceMethods = {}; Object.keys(def).forEach(function (key) { var value = def[key]; if (ReactStatics[key]) { Component[key] = value; } else if (ReactLifecycle[key]) { invariant_1(isFunction(value), 'Lifecycle method "%s" must be a function', key); // Keep React lifecycle methods on the prototype, for efficiency. proto[key] = function (a, b) { return value(this, a, b); }; } else if (!MyLifecycle[key]) { invariant_1(isFunction(value), 'Unable to bind property "%s"; it must be a function', key); // Save this method to be bound directly to the object at creation. instanceMethods[key] = value; } }); // Use the names of functions as the displayName. if (!Component.displayName && isFunction(def)) { Component.displayName = def.name; } return Component; } /** * A cache of dynamically-created components. */ var cache = new Map(); /** * Creates a new React element using a component definition. New components * are automatically created from definitions on-the-fly as needed. */ function createElement() { var args = Array.prototype.slice.call(arguments, 0); var def = args.shift(); invariant_1(def, "createElement needs a component definition"); var component = typeof def === "string" || typeof def === "function" ? def : cache.get(def); if (component == null) { component = createComponent(def); cache.set(def, component); } args.unshift(component); return React.createElement.apply(React, args); } var index = { createComponent: createComponent, createElement: createElement }; export { createComponent, createElement }; export default index;