factory.js 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002
  1. /**
  2. * Copyright (c) 2013-present, Facebook, Inc.
  3. *
  4. * This source code is licensed under the MIT license found in the
  5. * LICENSE file in the root directory of this source tree.
  6. *
  7. */
  8. 'use strict';
  9. var _assign = require('object-assign');
  10. // -- Inlined from fbjs --
  11. var emptyObject = {};
  12. if (process.env.NODE_ENV !== 'production') {
  13. Object.freeze(emptyObject);
  14. }
  15. var validateFormat = function validateFormat(format) {};
  16. if (process.env.NODE_ENV !== 'production') {
  17. validateFormat = function validateFormat(format) {
  18. if (format === undefined) {
  19. throw new Error('invariant requires an error message argument');
  20. }
  21. };
  22. }
  23. function _invariant(condition, format, a, b, c, d, e, f) {
  24. validateFormat(format);
  25. if (!condition) {
  26. var error;
  27. if (format === undefined) {
  28. error = new Error('Minified exception occurred; use the non-minified dev environment ' + 'for the full error message and additional helpful warnings.');
  29. } else {
  30. var args = [a, b, c, d, e, f];
  31. var argIndex = 0;
  32. error = new Error(format.replace(/%s/g, function () {
  33. return args[argIndex++];
  34. }));
  35. error.name = 'Invariant Violation';
  36. }
  37. error.framesToPop = 1; // we don't care about invariant's own frame
  38. throw error;
  39. }
  40. }
  41. var warning = function(){};
  42. if (process.env.NODE_ENV !== 'production') {
  43. var printWarning = function printWarning(format) {
  44. for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
  45. args[_key - 1] = arguments[_key];
  46. }
  47. var argIndex = 0;
  48. var message = 'Warning: ' + format.replace(/%s/g, function () {
  49. return args[argIndex++];
  50. });
  51. if (typeof console !== 'undefined') {
  52. console.error(message);
  53. }
  54. try {
  55. // --- Welcome to debugging React ---
  56. // This error was thrown as a convenience so that you can use this stack
  57. // to find the callsite that caused this warning to fire.
  58. throw new Error(message);
  59. } catch (x) {}
  60. };
  61. warning = function warning(condition, format) {
  62. if (format === undefined) {
  63. throw new Error('`warning(condition, format, ...args)` requires a warning ' + 'message argument');
  64. }
  65. if (format.indexOf('Failed Composite propType: ') === 0) {
  66. return; // Ignore CompositeComponent proptype check.
  67. }
  68. if (!condition) {
  69. for (var _len2 = arguments.length, args = Array(_len2 > 2 ? _len2 - 2 : 0), _key2 = 2; _key2 < _len2; _key2++) {
  70. args[_key2 - 2] = arguments[_key2];
  71. }
  72. printWarning.apply(undefined, [format].concat(args));
  73. }
  74. };
  75. }
  76. // /-- Inlined from fbjs --
  77. var MIXINS_KEY = 'mixins';
  78. // Helper function to allow the creation of anonymous functions which do not
  79. // have .name set to the name of the variable being assigned to.
  80. function identity(fn) {
  81. return fn;
  82. }
  83. var ReactPropTypeLocationNames;
  84. if (process.env.NODE_ENV !== 'production') {
  85. ReactPropTypeLocationNames = {
  86. prop: 'prop',
  87. context: 'context',
  88. childContext: 'child context'
  89. };
  90. } else {
  91. ReactPropTypeLocationNames = {};
  92. }
  93. function factory(ReactComponent, isValidElement, ReactNoopUpdateQueue) {
  94. /**
  95. * Policies that describe methods in `ReactClassInterface`.
  96. */
  97. var injectedMixins = [];
  98. /**
  99. * Composite components are higher-level components that compose other composite
  100. * or host components.
  101. *
  102. * To create a new type of `ReactClass`, pass a specification of
  103. * your new class to `React.createClass`. The only requirement of your class
  104. * specification is that you implement a `render` method.
  105. *
  106. * var MyComponent = React.createClass({
  107. * render: function() {
  108. * return <div>Hello World</div>;
  109. * }
  110. * });
  111. *
  112. * The class specification supports a specific protocol of methods that have
  113. * special meaning (e.g. `render`). See `ReactClassInterface` for
  114. * more the comprehensive protocol. Any other properties and methods in the
  115. * class specification will be available on the prototype.
  116. *
  117. * @interface ReactClassInterface
  118. * @internal
  119. */
  120. var ReactClassInterface = {
  121. /**
  122. * An array of Mixin objects to include when defining your component.
  123. *
  124. * @type {array}
  125. * @optional
  126. */
  127. mixins: 'DEFINE_MANY',
  128. /**
  129. * An object containing properties and methods that should be defined on
  130. * the component's constructor instead of its prototype (static methods).
  131. *
  132. * @type {object}
  133. * @optional
  134. */
  135. statics: 'DEFINE_MANY',
  136. /**
  137. * Definition of prop types for this component.
  138. *
  139. * @type {object}
  140. * @optional
  141. */
  142. propTypes: 'DEFINE_MANY',
  143. /**
  144. * Definition of context types for this component.
  145. *
  146. * @type {object}
  147. * @optional
  148. */
  149. contextTypes: 'DEFINE_MANY',
  150. /**
  151. * Definition of context types this component sets for its children.
  152. *
  153. * @type {object}
  154. * @optional
  155. */
  156. childContextTypes: 'DEFINE_MANY',
  157. // ==== Definition methods ====
  158. /**
  159. * Invoked when the component is mounted. Values in the mapping will be set on
  160. * `this.props` if that prop is not specified (i.e. using an `in` check).
  161. *
  162. * This method is invoked before `getInitialState` and therefore cannot rely
  163. * on `this.state` or use `this.setState`.
  164. *
  165. * @return {object}
  166. * @optional
  167. */
  168. getDefaultProps: 'DEFINE_MANY_MERGED',
  169. /**
  170. * Invoked once before the component is mounted. The return value will be used
  171. * as the initial value of `this.state`.
  172. *
  173. * getInitialState: function() {
  174. * return {
  175. * isOn: false,
  176. * fooBaz: new BazFoo()
  177. * }
  178. * }
  179. *
  180. * @return {object}
  181. * @optional
  182. */
  183. getInitialState: 'DEFINE_MANY_MERGED',
  184. /**
  185. * @return {object}
  186. * @optional
  187. */
  188. getChildContext: 'DEFINE_MANY_MERGED',
  189. /**
  190. * Uses props from `this.props` and state from `this.state` to render the
  191. * structure of the component.
  192. *
  193. * No guarantees are made about when or how often this method is invoked, so
  194. * it must not have side effects.
  195. *
  196. * render: function() {
  197. * var name = this.props.name;
  198. * return <div>Hello, {name}!</div>;
  199. * }
  200. *
  201. * @return {ReactComponent}
  202. * @required
  203. */
  204. render: 'DEFINE_ONCE',
  205. // ==== Delegate methods ====
  206. /**
  207. * Invoked when the component is initially created and about to be mounted.
  208. * This may have side effects, but any external subscriptions or data created
  209. * by this method must be cleaned up in `componentWillUnmount`.
  210. *
  211. * @optional
  212. */
  213. componentWillMount: 'DEFINE_MANY',
  214. /**
  215. * Invoked when the component has been mounted and has a DOM representation.
  216. * However, there is no guarantee that the DOM node is in the document.
  217. *
  218. * Use this as an opportunity to operate on the DOM when the component has
  219. * been mounted (initialized and rendered) for the first time.
  220. *
  221. * @param {DOMElement} rootNode DOM element representing the component.
  222. * @optional
  223. */
  224. componentDidMount: 'DEFINE_MANY',
  225. /**
  226. * Invoked before the component receives new props.
  227. *
  228. * Use this as an opportunity to react to a prop transition by updating the
  229. * state using `this.setState`. Current props are accessed via `this.props`.
  230. *
  231. * componentWillReceiveProps: function(nextProps, nextContext) {
  232. * this.setState({
  233. * likesIncreasing: nextProps.likeCount > this.props.likeCount
  234. * });
  235. * }
  236. *
  237. * NOTE: There is no equivalent `componentWillReceiveState`. An incoming prop
  238. * transition may cause a state change, but the opposite is not true. If you
  239. * need it, you are probably looking for `componentWillUpdate`.
  240. *
  241. * @param {object} nextProps
  242. * @optional
  243. */
  244. componentWillReceiveProps: 'DEFINE_MANY',
  245. /**
  246. * Invoked while deciding if the component should be updated as a result of
  247. * receiving new props, state and/or context.
  248. *
  249. * Use this as an opportunity to `return false` when you're certain that the
  250. * transition to the new props/state/context will not require a component
  251. * update.
  252. *
  253. * shouldComponentUpdate: function(nextProps, nextState, nextContext) {
  254. * return !equal(nextProps, this.props) ||
  255. * !equal(nextState, this.state) ||
  256. * !equal(nextContext, this.context);
  257. * }
  258. *
  259. * @param {object} nextProps
  260. * @param {?object} nextState
  261. * @param {?object} nextContext
  262. * @return {boolean} True if the component should update.
  263. * @optional
  264. */
  265. shouldComponentUpdate: 'DEFINE_ONCE',
  266. /**
  267. * Invoked when the component is about to update due to a transition from
  268. * `this.props`, `this.state` and `this.context` to `nextProps`, `nextState`
  269. * and `nextContext`.
  270. *
  271. * Use this as an opportunity to perform preparation before an update occurs.
  272. *
  273. * NOTE: You **cannot** use `this.setState()` in this method.
  274. *
  275. * @param {object} nextProps
  276. * @param {?object} nextState
  277. * @param {?object} nextContext
  278. * @param {ReactReconcileTransaction} transaction
  279. * @optional
  280. */
  281. componentWillUpdate: 'DEFINE_MANY',
  282. /**
  283. * Invoked when the component's DOM representation has been updated.
  284. *
  285. * Use this as an opportunity to operate on the DOM when the component has
  286. * been updated.
  287. *
  288. * @param {object} prevProps
  289. * @param {?object} prevState
  290. * @param {?object} prevContext
  291. * @param {DOMElement} rootNode DOM element representing the component.
  292. * @optional
  293. */
  294. componentDidUpdate: 'DEFINE_MANY',
  295. /**
  296. * Invoked when the component is about to be removed from its parent and have
  297. * its DOM representation destroyed.
  298. *
  299. * Use this as an opportunity to deallocate any external resources.
  300. *
  301. * NOTE: There is no `componentDidUnmount` since your component will have been
  302. * destroyed by that point.
  303. *
  304. * @optional
  305. */
  306. componentWillUnmount: 'DEFINE_MANY',
  307. /**
  308. * Replacement for (deprecated) `componentWillMount`.
  309. *
  310. * @optional
  311. */
  312. UNSAFE_componentWillMount: 'DEFINE_MANY',
  313. /**
  314. * Replacement for (deprecated) `componentWillReceiveProps`.
  315. *
  316. * @optional
  317. */
  318. UNSAFE_componentWillReceiveProps: 'DEFINE_MANY',
  319. /**
  320. * Replacement for (deprecated) `componentWillUpdate`.
  321. *
  322. * @optional
  323. */
  324. UNSAFE_componentWillUpdate: 'DEFINE_MANY',
  325. // ==== Advanced methods ====
  326. /**
  327. * Updates the component's currently mounted DOM representation.
  328. *
  329. * By default, this implements React's rendering and reconciliation algorithm.
  330. * Sophisticated clients may wish to override this.
  331. *
  332. * @param {ReactReconcileTransaction} transaction
  333. * @internal
  334. * @overridable
  335. */
  336. updateComponent: 'OVERRIDE_BASE'
  337. };
  338. /**
  339. * Similar to ReactClassInterface but for static methods.
  340. */
  341. var ReactClassStaticInterface = {
  342. /**
  343. * This method is invoked after a component is instantiated and when it
  344. * receives new props. Return an object to update state in response to
  345. * prop changes. Return null to indicate no change to state.
  346. *
  347. * If an object is returned, its keys will be merged into the existing state.
  348. *
  349. * @return {object || null}
  350. * @optional
  351. */
  352. getDerivedStateFromProps: 'DEFINE_MANY_MERGED'
  353. };
  354. /**
  355. * Mapping from class specification keys to special processing functions.
  356. *
  357. * Although these are declared like instance properties in the specification
  358. * when defining classes using `React.createClass`, they are actually static
  359. * and are accessible on the constructor instead of the prototype. Despite
  360. * being static, they must be defined outside of the "statics" key under
  361. * which all other static methods are defined.
  362. */
  363. var RESERVED_SPEC_KEYS = {
  364. displayName: function(Constructor, displayName) {
  365. Constructor.displayName = displayName;
  366. },
  367. mixins: function(Constructor, mixins) {
  368. if (mixins) {
  369. for (var i = 0; i < mixins.length; i++) {
  370. mixSpecIntoComponent(Constructor, mixins[i]);
  371. }
  372. }
  373. },
  374. childContextTypes: function(Constructor, childContextTypes) {
  375. if (process.env.NODE_ENV !== 'production') {
  376. validateTypeDef(Constructor, childContextTypes, 'childContext');
  377. }
  378. Constructor.childContextTypes = _assign(
  379. {},
  380. Constructor.childContextTypes,
  381. childContextTypes
  382. );
  383. },
  384. contextTypes: function(Constructor, contextTypes) {
  385. if (process.env.NODE_ENV !== 'production') {
  386. validateTypeDef(Constructor, contextTypes, 'context');
  387. }
  388. Constructor.contextTypes = _assign(
  389. {},
  390. Constructor.contextTypes,
  391. contextTypes
  392. );
  393. },
  394. /**
  395. * Special case getDefaultProps which should move into statics but requires
  396. * automatic merging.
  397. */
  398. getDefaultProps: function(Constructor, getDefaultProps) {
  399. if (Constructor.getDefaultProps) {
  400. Constructor.getDefaultProps = createMergedResultFunction(
  401. Constructor.getDefaultProps,
  402. getDefaultProps
  403. );
  404. } else {
  405. Constructor.getDefaultProps = getDefaultProps;
  406. }
  407. },
  408. propTypes: function(Constructor, propTypes) {
  409. if (process.env.NODE_ENV !== 'production') {
  410. validateTypeDef(Constructor, propTypes, 'prop');
  411. }
  412. Constructor.propTypes = _assign({}, Constructor.propTypes, propTypes);
  413. },
  414. statics: function(Constructor, statics) {
  415. mixStaticSpecIntoComponent(Constructor, statics);
  416. },
  417. autobind: function() {}
  418. };
  419. function validateTypeDef(Constructor, typeDef, location) {
  420. for (var propName in typeDef) {
  421. if (typeDef.hasOwnProperty(propName)) {
  422. // use a warning instead of an _invariant so components
  423. // don't show up in prod but only in __DEV__
  424. if (process.env.NODE_ENV !== 'production') {
  425. warning(
  426. typeof typeDef[propName] === 'function',
  427. '%s: %s type `%s` is invalid; it must be a function, usually from ' +
  428. 'React.PropTypes.',
  429. Constructor.displayName || 'ReactClass',
  430. ReactPropTypeLocationNames[location],
  431. propName
  432. );
  433. }
  434. }
  435. }
  436. }
  437. function validateMethodOverride(isAlreadyDefined, name) {
  438. var specPolicy = ReactClassInterface.hasOwnProperty(name)
  439. ? ReactClassInterface[name]
  440. : null;
  441. // Disallow overriding of base class methods unless explicitly allowed.
  442. if (ReactClassMixin.hasOwnProperty(name)) {
  443. _invariant(
  444. specPolicy === 'OVERRIDE_BASE',
  445. 'ReactClassInterface: You are attempting to override ' +
  446. '`%s` from your class specification. Ensure that your method names ' +
  447. 'do not overlap with React methods.',
  448. name
  449. );
  450. }
  451. // Disallow defining methods more than once unless explicitly allowed.
  452. if (isAlreadyDefined) {
  453. _invariant(
  454. specPolicy === 'DEFINE_MANY' || specPolicy === 'DEFINE_MANY_MERGED',
  455. 'ReactClassInterface: You are attempting to define ' +
  456. '`%s` on your component more than once. This conflict may be due ' +
  457. 'to a mixin.',
  458. name
  459. );
  460. }
  461. }
  462. /**
  463. * Mixin helper which handles policy validation and reserved
  464. * specification keys when building React classes.
  465. */
  466. function mixSpecIntoComponent(Constructor, spec) {
  467. if (!spec) {
  468. if (process.env.NODE_ENV !== 'production') {
  469. var typeofSpec = typeof spec;
  470. var isMixinValid = typeofSpec === 'object' && spec !== null;
  471. if (process.env.NODE_ENV !== 'production') {
  472. warning(
  473. isMixinValid,
  474. "%s: You're attempting to include a mixin that is either null " +
  475. 'or not an object. Check the mixins included by the component, ' +
  476. 'as well as any mixins they include themselves. ' +
  477. 'Expected object but got %s.',
  478. Constructor.displayName || 'ReactClass',
  479. spec === null ? null : typeofSpec
  480. );
  481. }
  482. }
  483. return;
  484. }
  485. _invariant(
  486. typeof spec !== 'function',
  487. "ReactClass: You're attempting to " +
  488. 'use a component class or function as a mixin. Instead, just use a ' +
  489. 'regular object.'
  490. );
  491. _invariant(
  492. !isValidElement(spec),
  493. "ReactClass: You're attempting to " +
  494. 'use a component as a mixin. Instead, just use a regular object.'
  495. );
  496. var proto = Constructor.prototype;
  497. var autoBindPairs = proto.__reactAutoBindPairs;
  498. // By handling mixins before any other properties, we ensure the same
  499. // chaining order is applied to methods with DEFINE_MANY policy, whether
  500. // mixins are listed before or after these methods in the spec.
  501. if (spec.hasOwnProperty(MIXINS_KEY)) {
  502. RESERVED_SPEC_KEYS.mixins(Constructor, spec.mixins);
  503. }
  504. for (var name in spec) {
  505. if (!spec.hasOwnProperty(name)) {
  506. continue;
  507. }
  508. if (name === MIXINS_KEY) {
  509. // We have already handled mixins in a special case above.
  510. continue;
  511. }
  512. var property = spec[name];
  513. var isAlreadyDefined = proto.hasOwnProperty(name);
  514. validateMethodOverride(isAlreadyDefined, name);
  515. if (RESERVED_SPEC_KEYS.hasOwnProperty(name)) {
  516. RESERVED_SPEC_KEYS[name](Constructor, property);
  517. } else {
  518. // Setup methods on prototype:
  519. // The following member methods should not be automatically bound:
  520. // 1. Expected ReactClass methods (in the "interface").
  521. // 2. Overridden methods (that were mixed in).
  522. var isReactClassMethod = ReactClassInterface.hasOwnProperty(name);
  523. var isFunction = typeof property === 'function';
  524. var shouldAutoBind =
  525. isFunction &&
  526. !isReactClassMethod &&
  527. !isAlreadyDefined &&
  528. spec.autobind !== false;
  529. if (shouldAutoBind) {
  530. autoBindPairs.push(name, property);
  531. proto[name] = property;
  532. } else {
  533. if (isAlreadyDefined) {
  534. var specPolicy = ReactClassInterface[name];
  535. // These cases should already be caught by validateMethodOverride.
  536. _invariant(
  537. isReactClassMethod &&
  538. (specPolicy === 'DEFINE_MANY_MERGED' ||
  539. specPolicy === 'DEFINE_MANY'),
  540. 'ReactClass: Unexpected spec policy %s for key %s ' +
  541. 'when mixing in component specs.',
  542. specPolicy,
  543. name
  544. );
  545. // For methods which are defined more than once, call the existing
  546. // methods before calling the new property, merging if appropriate.
  547. if (specPolicy === 'DEFINE_MANY_MERGED') {
  548. proto[name] = createMergedResultFunction(proto[name], property);
  549. } else if (specPolicy === 'DEFINE_MANY') {
  550. proto[name] = createChainedFunction(proto[name], property);
  551. }
  552. } else {
  553. proto[name] = property;
  554. if (process.env.NODE_ENV !== 'production') {
  555. // Add verbose displayName to the function, which helps when looking
  556. // at profiling tools.
  557. if (typeof property === 'function' && spec.displayName) {
  558. proto[name].displayName = spec.displayName + '_' + name;
  559. }
  560. }
  561. }
  562. }
  563. }
  564. }
  565. }
  566. function mixStaticSpecIntoComponent(Constructor, statics) {
  567. if (!statics) {
  568. return;
  569. }
  570. for (var name in statics) {
  571. var property = statics[name];
  572. if (!statics.hasOwnProperty(name)) {
  573. continue;
  574. }
  575. var isReserved = name in RESERVED_SPEC_KEYS;
  576. _invariant(
  577. !isReserved,
  578. 'ReactClass: You are attempting to define a reserved ' +
  579. 'property, `%s`, that shouldn\'t be on the "statics" key. Define it ' +
  580. 'as an instance property instead; it will still be accessible on the ' +
  581. 'constructor.',
  582. name
  583. );
  584. var isAlreadyDefined = name in Constructor;
  585. if (isAlreadyDefined) {
  586. var specPolicy = ReactClassStaticInterface.hasOwnProperty(name)
  587. ? ReactClassStaticInterface[name]
  588. : null;
  589. _invariant(
  590. specPolicy === 'DEFINE_MANY_MERGED',
  591. 'ReactClass: You are attempting to define ' +
  592. '`%s` on your component more than once. This conflict may be ' +
  593. 'due to a mixin.',
  594. name
  595. );
  596. Constructor[name] = createMergedResultFunction(Constructor[name], property);
  597. return;
  598. }
  599. Constructor[name] = property;
  600. }
  601. }
  602. /**
  603. * Merge two objects, but throw if both contain the same key.
  604. *
  605. * @param {object} one The first object, which is mutated.
  606. * @param {object} two The second object
  607. * @return {object} one after it has been mutated to contain everything in two.
  608. */
  609. function mergeIntoWithNoDuplicateKeys(one, two) {
  610. _invariant(
  611. one && two && typeof one === 'object' && typeof two === 'object',
  612. 'mergeIntoWithNoDuplicateKeys(): Cannot merge non-objects.'
  613. );
  614. for (var key in two) {
  615. if (two.hasOwnProperty(key)) {
  616. _invariant(
  617. one[key] === undefined,
  618. 'mergeIntoWithNoDuplicateKeys(): ' +
  619. 'Tried to merge two objects with the same key: `%s`. This conflict ' +
  620. 'may be due to a mixin; in particular, this may be caused by two ' +
  621. 'getInitialState() or getDefaultProps() methods returning objects ' +
  622. 'with clashing keys.',
  623. key
  624. );
  625. one[key] = two[key];
  626. }
  627. }
  628. return one;
  629. }
  630. /**
  631. * Creates a function that invokes two functions and merges their return values.
  632. *
  633. * @param {function} one Function to invoke first.
  634. * @param {function} two Function to invoke second.
  635. * @return {function} Function that invokes the two argument functions.
  636. * @private
  637. */
  638. function createMergedResultFunction(one, two) {
  639. return function mergedResult() {
  640. var a = one.apply(this, arguments);
  641. var b = two.apply(this, arguments);
  642. if (a == null) {
  643. return b;
  644. } else if (b == null) {
  645. return a;
  646. }
  647. var c = {};
  648. mergeIntoWithNoDuplicateKeys(c, a);
  649. mergeIntoWithNoDuplicateKeys(c, b);
  650. return c;
  651. };
  652. }
  653. /**
  654. * Creates a function that invokes two functions and ignores their return vales.
  655. *
  656. * @param {function} one Function to invoke first.
  657. * @param {function} two Function to invoke second.
  658. * @return {function} Function that invokes the two argument functions.
  659. * @private
  660. */
  661. function createChainedFunction(one, two) {
  662. return function chainedFunction() {
  663. one.apply(this, arguments);
  664. two.apply(this, arguments);
  665. };
  666. }
  667. /**
  668. * Binds a method to the component.
  669. *
  670. * @param {object} component Component whose method is going to be bound.
  671. * @param {function} method Method to be bound.
  672. * @return {function} The bound method.
  673. */
  674. function bindAutoBindMethod(component, method) {
  675. var boundMethod = method.bind(component);
  676. if (process.env.NODE_ENV !== 'production') {
  677. boundMethod.__reactBoundContext = component;
  678. boundMethod.__reactBoundMethod = method;
  679. boundMethod.__reactBoundArguments = null;
  680. var componentName = component.constructor.displayName;
  681. var _bind = boundMethod.bind;
  682. boundMethod.bind = function(newThis) {
  683. for (
  684. var _len = arguments.length,
  685. args = Array(_len > 1 ? _len - 1 : 0),
  686. _key = 1;
  687. _key < _len;
  688. _key++
  689. ) {
  690. args[_key - 1] = arguments[_key];
  691. }
  692. // User is trying to bind() an autobound method; we effectively will
  693. // ignore the value of "this" that the user is trying to use, so
  694. // let's warn.
  695. if (newThis !== component && newThis !== null) {
  696. if (process.env.NODE_ENV !== 'production') {
  697. warning(
  698. false,
  699. 'bind(): React component methods may only be bound to the ' +
  700. 'component instance. See %s',
  701. componentName
  702. );
  703. }
  704. } else if (!args.length) {
  705. if (process.env.NODE_ENV !== 'production') {
  706. warning(
  707. false,
  708. 'bind(): You are binding a component method to the component. ' +
  709. 'React does this for you automatically in a high-performance ' +
  710. 'way, so you can safely remove this call. See %s',
  711. componentName
  712. );
  713. }
  714. return boundMethod;
  715. }
  716. var reboundMethod = _bind.apply(boundMethod, arguments);
  717. reboundMethod.__reactBoundContext = component;
  718. reboundMethod.__reactBoundMethod = method;
  719. reboundMethod.__reactBoundArguments = args;
  720. return reboundMethod;
  721. };
  722. }
  723. return boundMethod;
  724. }
  725. /**
  726. * Binds all auto-bound methods in a component.
  727. *
  728. * @param {object} component Component whose method is going to be bound.
  729. */
  730. function bindAutoBindMethods(component) {
  731. var pairs = component.__reactAutoBindPairs;
  732. for (var i = 0; i < pairs.length; i += 2) {
  733. var autoBindKey = pairs[i];
  734. var method = pairs[i + 1];
  735. component[autoBindKey] = bindAutoBindMethod(component, method);
  736. }
  737. }
  738. var IsMountedPreMixin = {
  739. componentDidMount: function() {
  740. this.__isMounted = true;
  741. }
  742. };
  743. var IsMountedPostMixin = {
  744. componentWillUnmount: function() {
  745. this.__isMounted = false;
  746. }
  747. };
  748. /**
  749. * Add more to the ReactClass base class. These are all legacy features and
  750. * therefore not already part of the modern ReactComponent.
  751. */
  752. var ReactClassMixin = {
  753. /**
  754. * TODO: This will be deprecated because state should always keep a consistent
  755. * type signature and the only use case for this, is to avoid that.
  756. */
  757. replaceState: function(newState, callback) {
  758. this.updater.enqueueReplaceState(this, newState, callback);
  759. },
  760. /**
  761. * Checks whether or not this composite component is mounted.
  762. * @return {boolean} True if mounted, false otherwise.
  763. * @protected
  764. * @final
  765. */
  766. isMounted: function() {
  767. if (process.env.NODE_ENV !== 'production') {
  768. warning(
  769. this.__didWarnIsMounted,
  770. '%s: isMounted is deprecated. Instead, make sure to clean up ' +
  771. 'subscriptions and pending requests in componentWillUnmount to ' +
  772. 'prevent memory leaks.',
  773. (this.constructor && this.constructor.displayName) ||
  774. this.name ||
  775. 'Component'
  776. );
  777. this.__didWarnIsMounted = true;
  778. }
  779. return !!this.__isMounted;
  780. }
  781. };
  782. var ReactClassComponent = function() {};
  783. _assign(
  784. ReactClassComponent.prototype,
  785. ReactComponent.prototype,
  786. ReactClassMixin
  787. );
  788. /**
  789. * Creates a composite component class given a class specification.
  790. * See https://facebook.github.io/react/docs/top-level-api.html#react.createclass
  791. *
  792. * @param {object} spec Class specification (which must define `render`).
  793. * @return {function} Component constructor function.
  794. * @public
  795. */
  796. function createClass(spec) {
  797. // To keep our warnings more understandable, we'll use a little hack here to
  798. // ensure that Constructor.name !== 'Constructor'. This makes sure we don't
  799. // unnecessarily identify a class without displayName as 'Constructor'.
  800. var Constructor = identity(function(props, context, updater) {
  801. // This constructor gets overridden by mocks. The argument is used
  802. // by mocks to assert on what gets mounted.
  803. if (process.env.NODE_ENV !== 'production') {
  804. warning(
  805. this instanceof Constructor,
  806. 'Something is calling a React component directly. Use a factory or ' +
  807. 'JSX instead. See: https://fb.me/react-legacyfactory'
  808. );
  809. }
  810. // Wire up auto-binding
  811. if (this.__reactAutoBindPairs.length) {
  812. bindAutoBindMethods(this);
  813. }
  814. this.props = props;
  815. this.context = context;
  816. this.refs = emptyObject;
  817. this.updater = updater || ReactNoopUpdateQueue;
  818. this.state = null;
  819. // ReactClasses doesn't have constructors. Instead, they use the
  820. // getInitialState and componentWillMount methods for initialization.
  821. var initialState = this.getInitialState ? this.getInitialState() : null;
  822. if (process.env.NODE_ENV !== 'production') {
  823. // We allow auto-mocks to proceed as if they're returning null.
  824. if (
  825. initialState === undefined &&
  826. this.getInitialState._isMockFunction
  827. ) {
  828. // This is probably bad practice. Consider warning here and
  829. // deprecating this convenience.
  830. initialState = null;
  831. }
  832. }
  833. _invariant(
  834. typeof initialState === 'object' && !Array.isArray(initialState),
  835. '%s.getInitialState(): must return an object or null',
  836. Constructor.displayName || 'ReactCompositeComponent'
  837. );
  838. this.state = initialState;
  839. });
  840. Constructor.prototype = new ReactClassComponent();
  841. Constructor.prototype.constructor = Constructor;
  842. Constructor.prototype.__reactAutoBindPairs = [];
  843. injectedMixins.forEach(mixSpecIntoComponent.bind(null, Constructor));
  844. mixSpecIntoComponent(Constructor, IsMountedPreMixin);
  845. mixSpecIntoComponent(Constructor, spec);
  846. mixSpecIntoComponent(Constructor, IsMountedPostMixin);
  847. // Initialize the defaultProps property after all mixins have been merged.
  848. if (Constructor.getDefaultProps) {
  849. Constructor.defaultProps = Constructor.getDefaultProps();
  850. }
  851. if (process.env.NODE_ENV !== 'production') {
  852. // This is a tag to indicate that the use of these method names is ok,
  853. // since it's used with createClass. If it's not, then it's likely a
  854. // mistake so we'll warn you to use the static property, property
  855. // initializer or constructor respectively.
  856. if (Constructor.getDefaultProps) {
  857. Constructor.getDefaultProps.isReactClassApproved = {};
  858. }
  859. if (Constructor.prototype.getInitialState) {
  860. Constructor.prototype.getInitialState.isReactClassApproved = {};
  861. }
  862. }
  863. _invariant(
  864. Constructor.prototype.render,
  865. 'createClass(...): Class specification must implement a `render` method.'
  866. );
  867. if (process.env.NODE_ENV !== 'production') {
  868. warning(
  869. !Constructor.prototype.componentShouldUpdate,
  870. '%s has a method called ' +
  871. 'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' +
  872. 'The name is phrased as a question because the function is ' +
  873. 'expected to return a value.',
  874. spec.displayName || 'A component'
  875. );
  876. warning(
  877. !Constructor.prototype.componentWillRecieveProps,
  878. '%s has a method called ' +
  879. 'componentWillRecieveProps(). Did you mean componentWillReceiveProps()?',
  880. spec.displayName || 'A component'
  881. );
  882. warning(
  883. !Constructor.prototype.UNSAFE_componentWillRecieveProps,
  884. '%s has a method called UNSAFE_componentWillRecieveProps(). ' +
  885. 'Did you mean UNSAFE_componentWillReceiveProps()?',
  886. spec.displayName || 'A component'
  887. );
  888. }
  889. // Reduce time spent doing lookups by setting these on the prototype.
  890. for (var methodName in ReactClassInterface) {
  891. if (!Constructor.prototype[methodName]) {
  892. Constructor.prototype[methodName] = null;
  893. }
  894. }
  895. return Constructor;
  896. }
  897. return createClass;
  898. }
  899. module.exports = factory;