react/src/isomorphic/classic/element/ReactElement.js

336 lines
10 KiB
JavaScript
Raw Normal View History

/**
* Copyright 2014-present, Facebook, Inc.
2014-10-09 08:27:59 +08:00
* All rights reserved.
*
2014-10-09 08:27:59 +08:00
* 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.
*
* @providesModule ReactElement
*/
'use strict';
var ReactCurrentOwner = require('ReactCurrentOwner');
var assign = require('Object.assign');
var warning = require('warning');
var canDefineProperty = require('canDefineProperty');
Use a Symbol to tag every ReactElement Fixes #3473 I tag each React element with `$$typeof: Symbol.for('react.element')`. We need this to be able to safely distinguish these from plain objects that might have come from user provided JSON. The idiomatic JavaScript way of tagging an object is for it to inherent some prototype and then use `instanceof` to test for it. However, this has limitations since it doesn't work with value types which require `typeof` checks. They also don't work across realms. Which is why there are alternative tag checks like `Array.isArray` or the `toStringTag`. Another problem is that different instances of React that might have been created not knowing about eachother. npm tends to make this kind of problem occur a lot. Additionally, it is our hope that ReactElement will one day be specified in terms of a "Value Type" style record instead of a plain Object. This Value Types proposal by @nikomatsakis is currently on hold but does satisfy all these requirements: https://github.com/nikomatsakis/typed-objects-explainer/blob/master/valuetypes.md#the-typeof-operator Additionally, there is already a system for coordinating tags across module systems and even realms in ES6. Namely using `Symbol.for`. Currently these objects are not able to transfer between Workers but there is nothing preventing that from being possible in the future. You could imagine even `Symbol.for` working across Worker boundaries. You could also build a system that coordinates Symbols and Value Types from server to client or through serialized forms. That's beyond the scope of React itself, and if it was built it seems like it would belong with the `Symbol` system. A system could override the `Symbol.for('react.element')` to return a plain yet cryptographically random or unique number. That would allow ReactElements to pass through JSON without risking the XSS issue. The fallback solution is a plain well-known number. This makes it unsafe with regard to the XSS issue described in #3473. We could have used a much more convoluted solution to protect against JSON specifically but that would require some kind of significant coordination, or change the check to do a `typeof element.$$typeof === 'function'` check which would not make it unique to React. It seems cleaner to just use a fixed number since the protection is just a secondary layer anyway. I'm not sure if this is the right tradeoff. In short, if you want the XSS protection, use a proper Symbol polyfill. Finally, the reason for calling it `$$typeof` is to avoid confusion with `.type` and the use case is to add a tag that the `typeof` operator would refer to. I would use `@@typeof` but that seems to deopt in JSC. I also don't use `__typeof` because this is more than a framework private. It should really be part of the polyfilling layer.
2015-09-10 14:19:00 +08:00
// The Symbol used to tag the ReactElement type. If there is no native Symbol
// nor polyfill, then a plain number is used for performance.
var REACT_ELEMENT_TYPE =
(typeof Symbol === 'function' && Symbol.for && Symbol.for('react.element')) ||
0xeac7;
Use a Symbol to tag every ReactElement Fixes #3473 I tag each React element with `$$typeof: Symbol.for('react.element')`. We need this to be able to safely distinguish these from plain objects that might have come from user provided JSON. The idiomatic JavaScript way of tagging an object is for it to inherent some prototype and then use `instanceof` to test for it. However, this has limitations since it doesn't work with value types which require `typeof` checks. They also don't work across realms. Which is why there are alternative tag checks like `Array.isArray` or the `toStringTag`. Another problem is that different instances of React that might have been created not knowing about eachother. npm tends to make this kind of problem occur a lot. Additionally, it is our hope that ReactElement will one day be specified in terms of a "Value Type" style record instead of a plain Object. This Value Types proposal by @nikomatsakis is currently on hold but does satisfy all these requirements: https://github.com/nikomatsakis/typed-objects-explainer/blob/master/valuetypes.md#the-typeof-operator Additionally, there is already a system for coordinating tags across module systems and even realms in ES6. Namely using `Symbol.for`. Currently these objects are not able to transfer between Workers but there is nothing preventing that from being possible in the future. You could imagine even `Symbol.for` working across Worker boundaries. You could also build a system that coordinates Symbols and Value Types from server to client or through serialized forms. That's beyond the scope of React itself, and if it was built it seems like it would belong with the `Symbol` system. A system could override the `Symbol.for('react.element')` to return a plain yet cryptographically random or unique number. That would allow ReactElements to pass through JSON without risking the XSS issue. The fallback solution is a plain well-known number. This makes it unsafe with regard to the XSS issue described in #3473. We could have used a much more convoluted solution to protect against JSON specifically but that would require some kind of significant coordination, or change the check to do a `typeof element.$$typeof === 'function'` check which would not make it unique to React. It seems cleaner to just use a fixed number since the protection is just a secondary layer anyway. I'm not sure if this is the right tradeoff. In short, if you want the XSS protection, use a proper Symbol polyfill. Finally, the reason for calling it `$$typeof` is to avoid confusion with `.type` and the use case is to add a tag that the `typeof` operator would refer to. I would use `@@typeof` but that seems to deopt in JSC. I also don't use `__typeof` because this is more than a framework private. It should really be part of the polyfilling layer.
2015-09-10 14:19:00 +08:00
var RESERVED_PROPS = {
key: true,
ref: true,
__self: true,
__source: true,
};
var specialPropKeyWarningShown, specialPropRefWarningShown;
/**
* Factory method to create a new React element. This no longer adheres to
* the class pattern, so do not use new to call it. Also, no instanceof check
* will work. Instead test $$typeof field against Symbol.for('react.element') to check
* if something is a React Element.
*
* @param {*} type
* @param {*} key
* @param {string|object} ref
* @param {*} self A *temporary* helper to detect places where `this` is
* different from the `owner` when React.createElement is called, so that we
* can warn. We want to get rid of owner and replace string `ref`s with arrow
* functions, and as long as `this` and owner are the same, there will be no
* change in behavior.
* @param {*} source An annotation object (added by a transpiler or otherwise)
* indicating filename, line number, and/or other information.
* @param {*} owner
2014-10-19 23:31:45 +08:00
* @param {*} props
* @internal
*/
var ReactElement = function(type, key, ref, self, source, owner, props) {
var element = {
Use a Symbol to tag every ReactElement Fixes #3473 I tag each React element with `$$typeof: Symbol.for('react.element')`. We need this to be able to safely distinguish these from plain objects that might have come from user provided JSON. The idiomatic JavaScript way of tagging an object is for it to inherent some prototype and then use `instanceof` to test for it. However, this has limitations since it doesn't work with value types which require `typeof` checks. They also don't work across realms. Which is why there are alternative tag checks like `Array.isArray` or the `toStringTag`. Another problem is that different instances of React that might have been created not knowing about eachother. npm tends to make this kind of problem occur a lot. Additionally, it is our hope that ReactElement will one day be specified in terms of a "Value Type" style record instead of a plain Object. This Value Types proposal by @nikomatsakis is currently on hold but does satisfy all these requirements: https://github.com/nikomatsakis/typed-objects-explainer/blob/master/valuetypes.md#the-typeof-operator Additionally, there is already a system for coordinating tags across module systems and even realms in ES6. Namely using `Symbol.for`. Currently these objects are not able to transfer between Workers but there is nothing preventing that from being possible in the future. You could imagine even `Symbol.for` working across Worker boundaries. You could also build a system that coordinates Symbols and Value Types from server to client or through serialized forms. That's beyond the scope of React itself, and if it was built it seems like it would belong with the `Symbol` system. A system could override the `Symbol.for('react.element')` to return a plain yet cryptographically random or unique number. That would allow ReactElements to pass through JSON without risking the XSS issue. The fallback solution is a plain well-known number. This makes it unsafe with regard to the XSS issue described in #3473. We could have used a much more convoluted solution to protect against JSON specifically but that would require some kind of significant coordination, or change the check to do a `typeof element.$$typeof === 'function'` check which would not make it unique to React. It seems cleaner to just use a fixed number since the protection is just a secondary layer anyway. I'm not sure if this is the right tradeoff. In short, if you want the XSS protection, use a proper Symbol polyfill. Finally, the reason for calling it `$$typeof` is to avoid confusion with `.type` and the use case is to add a tag that the `typeof` operator would refer to. I would use `@@typeof` but that seems to deopt in JSC. I also don't use `__typeof` because this is more than a framework private. It should really be part of the polyfilling layer.
2015-09-10 14:19:00 +08:00
// This tag allow us to uniquely identify this as a React Element
$$typeof: REACT_ELEMENT_TYPE,
Use a Symbol to tag every ReactElement Fixes #3473 I tag each React element with `$$typeof: Symbol.for('react.element')`. We need this to be able to safely distinguish these from plain objects that might have come from user provided JSON. The idiomatic JavaScript way of tagging an object is for it to inherent some prototype and then use `instanceof` to test for it. However, this has limitations since it doesn't work with value types which require `typeof` checks. They also don't work across realms. Which is why there are alternative tag checks like `Array.isArray` or the `toStringTag`. Another problem is that different instances of React that might have been created not knowing about eachother. npm tends to make this kind of problem occur a lot. Additionally, it is our hope that ReactElement will one day be specified in terms of a "Value Type" style record instead of a plain Object. This Value Types proposal by @nikomatsakis is currently on hold but does satisfy all these requirements: https://github.com/nikomatsakis/typed-objects-explainer/blob/master/valuetypes.md#the-typeof-operator Additionally, there is already a system for coordinating tags across module systems and even realms in ES6. Namely using `Symbol.for`. Currently these objects are not able to transfer between Workers but there is nothing preventing that from being possible in the future. You could imagine even `Symbol.for` working across Worker boundaries. You could also build a system that coordinates Symbols and Value Types from server to client or through serialized forms. That's beyond the scope of React itself, and if it was built it seems like it would belong with the `Symbol` system. A system could override the `Symbol.for('react.element')` to return a plain yet cryptographically random or unique number. That would allow ReactElements to pass through JSON without risking the XSS issue. The fallback solution is a plain well-known number. This makes it unsafe with regard to the XSS issue described in #3473. We could have used a much more convoluted solution to protect against JSON specifically but that would require some kind of significant coordination, or change the check to do a `typeof element.$$typeof === 'function'` check which would not make it unique to React. It seems cleaner to just use a fixed number since the protection is just a secondary layer anyway. I'm not sure if this is the right tradeoff. In short, if you want the XSS protection, use a proper Symbol polyfill. Finally, the reason for calling it `$$typeof` is to avoid confusion with `.type` and the use case is to add a tag that the `typeof` operator would refer to. I would use `@@typeof` but that seems to deopt in JSC. I also don't use `__typeof` because this is more than a framework private. It should really be part of the polyfilling layer.
2015-09-10 14:19:00 +08:00
// Built-in properties that belong on the element
type: type,
key: key,
ref: ref,
Use a Symbol to tag every ReactElement Fixes #3473 I tag each React element with `$$typeof: Symbol.for('react.element')`. We need this to be able to safely distinguish these from plain objects that might have come from user provided JSON. The idiomatic JavaScript way of tagging an object is for it to inherent some prototype and then use `instanceof` to test for it. However, this has limitations since it doesn't work with value types which require `typeof` checks. They also don't work across realms. Which is why there are alternative tag checks like `Array.isArray` or the `toStringTag`. Another problem is that different instances of React that might have been created not knowing about eachother. npm tends to make this kind of problem occur a lot. Additionally, it is our hope that ReactElement will one day be specified in terms of a "Value Type" style record instead of a plain Object. This Value Types proposal by @nikomatsakis is currently on hold but does satisfy all these requirements: https://github.com/nikomatsakis/typed-objects-explainer/blob/master/valuetypes.md#the-typeof-operator Additionally, there is already a system for coordinating tags across module systems and even realms in ES6. Namely using `Symbol.for`. Currently these objects are not able to transfer between Workers but there is nothing preventing that from being possible in the future. You could imagine even `Symbol.for` working across Worker boundaries. You could also build a system that coordinates Symbols and Value Types from server to client or through serialized forms. That's beyond the scope of React itself, and if it was built it seems like it would belong with the `Symbol` system. A system could override the `Symbol.for('react.element')` to return a plain yet cryptographically random or unique number. That would allow ReactElements to pass through JSON without risking the XSS issue. The fallback solution is a plain well-known number. This makes it unsafe with regard to the XSS issue described in #3473. We could have used a much more convoluted solution to protect against JSON specifically but that would require some kind of significant coordination, or change the check to do a `typeof element.$$typeof === 'function'` check which would not make it unique to React. It seems cleaner to just use a fixed number since the protection is just a secondary layer anyway. I'm not sure if this is the right tradeoff. In short, if you want the XSS protection, use a proper Symbol polyfill. Finally, the reason for calling it `$$typeof` is to avoid confusion with `.type` and the use case is to add a tag that the `typeof` operator would refer to. I would use `@@typeof` but that seems to deopt in JSC. I also don't use `__typeof` because this is more than a framework private. It should really be part of the polyfilling layer.
2015-09-10 14:19:00 +08:00
props: props,
// Record the component responsible for creating this element.
_owner: owner,
};
if (__DEV__) {
2015-06-19 05:33:42 +08:00
// The validation flag is currently mutative. We put it on
// an external backing store so that we can freeze the whole object.
// This can be replaced with a WeakMap once they are implemented in
// commonly used development environments.
element._store = {};
// To make comparing ReactElements easier for testing purposes, we make
// the validation flag non-enumerable (where possible, which should
// include every environment we run tests in), so the test framework
// ignores it.
if (canDefineProperty) {
Object.defineProperty(element._store, 'validated', {
configurable: false,
enumerable: false,
writable: true,
2015-06-19 05:33:42 +08:00
value: false,
});
Use a Symbol to tag every ReactElement Fixes #3473 I tag each React element with `$$typeof: Symbol.for('react.element')`. We need this to be able to safely distinguish these from plain objects that might have come from user provided JSON. The idiomatic JavaScript way of tagging an object is for it to inherent some prototype and then use `instanceof` to test for it. However, this has limitations since it doesn't work with value types which require `typeof` checks. They also don't work across realms. Which is why there are alternative tag checks like `Array.isArray` or the `toStringTag`. Another problem is that different instances of React that might have been created not knowing about eachother. npm tends to make this kind of problem occur a lot. Additionally, it is our hope that ReactElement will one day be specified in terms of a "Value Type" style record instead of a plain Object. This Value Types proposal by @nikomatsakis is currently on hold but does satisfy all these requirements: https://github.com/nikomatsakis/typed-objects-explainer/blob/master/valuetypes.md#the-typeof-operator Additionally, there is already a system for coordinating tags across module systems and even realms in ES6. Namely using `Symbol.for`. Currently these objects are not able to transfer between Workers but there is nothing preventing that from being possible in the future. You could imagine even `Symbol.for` working across Worker boundaries. You could also build a system that coordinates Symbols and Value Types from server to client or through serialized forms. That's beyond the scope of React itself, and if it was built it seems like it would belong with the `Symbol` system. A system could override the `Symbol.for('react.element')` to return a plain yet cryptographically random or unique number. That would allow ReactElements to pass through JSON without risking the XSS issue. The fallback solution is a plain well-known number. This makes it unsafe with regard to the XSS issue described in #3473. We could have used a much more convoluted solution to protect against JSON specifically but that would require some kind of significant coordination, or change the check to do a `typeof element.$$typeof === 'function'` check which would not make it unique to React. It seems cleaner to just use a fixed number since the protection is just a secondary layer anyway. I'm not sure if this is the right tradeoff. In short, if you want the XSS protection, use a proper Symbol polyfill. Finally, the reason for calling it `$$typeof` is to avoid confusion with `.type` and the use case is to add a tag that the `typeof` operator would refer to. I would use `@@typeof` but that seems to deopt in JSC. I also don't use `__typeof` because this is more than a framework private. It should really be part of the polyfilling layer.
2015-09-10 14:19:00 +08:00
// self and source are DEV only properties.
Object.defineProperty(element, '_self', {
configurable: false,
enumerable: false,
writable: false,
value: self,
});
// Two elements created in two different places should be considered
// equal for testing purposes and therefore we hide it from enumeration.
Object.defineProperty(element, '_source', {
configurable: false,
enumerable: false,
writable: false,
value: source,
});
} else {
Use a Symbol to tag every ReactElement Fixes #3473 I tag each React element with `$$typeof: Symbol.for('react.element')`. We need this to be able to safely distinguish these from plain objects that might have come from user provided JSON. The idiomatic JavaScript way of tagging an object is for it to inherent some prototype and then use `instanceof` to test for it. However, this has limitations since it doesn't work with value types which require `typeof` checks. They also don't work across realms. Which is why there are alternative tag checks like `Array.isArray` or the `toStringTag`. Another problem is that different instances of React that might have been created not knowing about eachother. npm tends to make this kind of problem occur a lot. Additionally, it is our hope that ReactElement will one day be specified in terms of a "Value Type" style record instead of a plain Object. This Value Types proposal by @nikomatsakis is currently on hold but does satisfy all these requirements: https://github.com/nikomatsakis/typed-objects-explainer/blob/master/valuetypes.md#the-typeof-operator Additionally, there is already a system for coordinating tags across module systems and even realms in ES6. Namely using `Symbol.for`. Currently these objects are not able to transfer between Workers but there is nothing preventing that from being possible in the future. You could imagine even `Symbol.for` working across Worker boundaries. You could also build a system that coordinates Symbols and Value Types from server to client or through serialized forms. That's beyond the scope of React itself, and if it was built it seems like it would belong with the `Symbol` system. A system could override the `Symbol.for('react.element')` to return a plain yet cryptographically random or unique number. That would allow ReactElements to pass through JSON without risking the XSS issue. The fallback solution is a plain well-known number. This makes it unsafe with regard to the XSS issue described in #3473. We could have used a much more convoluted solution to protect against JSON specifically but that would require some kind of significant coordination, or change the check to do a `typeof element.$$typeof === 'function'` check which would not make it unique to React. It seems cleaner to just use a fixed number since the protection is just a secondary layer anyway. I'm not sure if this is the right tradeoff. In short, if you want the XSS protection, use a proper Symbol polyfill. Finally, the reason for calling it `$$typeof` is to avoid confusion with `.type` and the use case is to add a tag that the `typeof` operator would refer to. I would use `@@typeof` but that seems to deopt in JSC. I also don't use `__typeof` because this is more than a framework private. It should really be part of the polyfilling layer.
2015-09-10 14:19:00 +08:00
element._store.validated = false;
element._self = self;
element._source = source;
}
if (Object.freeze) {
Object.freeze(element.props);
Object.freeze(element);
}
}
return element;
};
ReactElement.createElement = function(type, config, children) {
var propName;
// Reserved names are extracted
var props = {};
var key = null;
var ref = null;
var self = null;
var source = null;
if (config != null) {
if (__DEV__) {
ref = !config.hasOwnProperty('ref') ||
Object.getOwnPropertyDescriptor(config, 'ref').get ? null : config.ref;
key = !config.hasOwnProperty('key') ||
Object.getOwnPropertyDescriptor(config, 'key').get ? null : '' + config.key;
} else {
ref = config.ref === undefined ? null : config.ref;
key = config.key === undefined ? null : '' + config.key;
}
self = config.__self === undefined ? null : config.__self;
source = config.__source === undefined ? null : config.__source;
// Remaining properties are added to a new props object
for (propName in config) {
if (config.hasOwnProperty(propName) &&
!RESERVED_PROPS.hasOwnProperty(propName)) {
props[propName] = config[propName];
}
}
}
// Children can be more than one argument, and those are transferred onto
// the newly allocated props object.
var childrenLength = arguments.length - 2;
if (childrenLength === 1) {
props.children = children;
} else if (childrenLength > 1) {
var childArray = Array(childrenLength);
for (var i = 0; i < childrenLength; i++) {
childArray[i] = arguments[i + 2];
}
props.children = childArray;
}
// Resolve default props
if (type && type.defaultProps) {
var defaultProps = type.defaultProps;
for (propName in defaultProps) {
if (props[propName] === undefined) {
props[propName] = defaultProps[propName];
}
}
}
if (__DEV__) {
// Create dummy `key` and `ref` property to `props` to warn users
// against its use
if (typeof props.$$typeof === 'undefined' ||
props.$$typeof !== REACT_ELEMENT_TYPE) {
if (!props.hasOwnProperty('key')) {
Object.defineProperty(props, 'key', {
get: function() {
if (!specialPropKeyWarningShown) {
specialPropKeyWarningShown = true;
warning(
false,
'%s: `key` is not a prop. Trying to access it will result ' +
'in `undefined` being returned. If you need to access the same ' +
'value within the child component, you should pass it as a different ' +
'prop. (https://fb.me/react-special-props)',
typeof type === 'function' && 'displayName' in type ? type.displayName : 'Element'
);
}
return undefined;
},
configurable: true,
});
}
if (!props.hasOwnProperty('ref')) {
Object.defineProperty(props, 'ref', {
get: function() {
if (!specialPropRefWarningShown) {
specialPropRefWarningShown = true;
warning(
false,
'%s: `ref` is not a prop. Trying to access it will result ' +
'in `undefined` being returned. If you need to access the same ' +
'value within the child component, you should pass it as a different ' +
'prop. (https://fb.me/react-special-props)',
typeof type === 'function' && 'displayName' in type ? type.displayName : 'Element'
);
}
return undefined;
},
configurable: true,
});
}
}
}
return ReactElement(
type,
key,
ref,
self,
source,
ReactCurrentOwner.current,
props
);
};
ReactElement.createFactory = function(type) {
var factory = ReactElement.createElement.bind(null, type);
// Expose the type on the factory and the prototype so that it can be
// easily accessed on elements. E.g. `<Foo />.type === Foo`.
// This should not be named `constructor` since this may not be the function
// that created the element, and it may not even be a constructor.
// Legacy hook TODO: Warn if this is accessed
factory.type = type;
return factory;
};
2015-04-11 15:55:58 +08:00
ReactElement.cloneAndReplaceKey = function(oldElement, newKey) {
Use a Symbol to tag every ReactElement Fixes #3473 I tag each React element with `$$typeof: Symbol.for('react.element')`. We need this to be able to safely distinguish these from plain objects that might have come from user provided JSON. The idiomatic JavaScript way of tagging an object is for it to inherent some prototype and then use `instanceof` to test for it. However, this has limitations since it doesn't work with value types which require `typeof` checks. They also don't work across realms. Which is why there are alternative tag checks like `Array.isArray` or the `toStringTag`. Another problem is that different instances of React that might have been created not knowing about eachother. npm tends to make this kind of problem occur a lot. Additionally, it is our hope that ReactElement will one day be specified in terms of a "Value Type" style record instead of a plain Object. This Value Types proposal by @nikomatsakis is currently on hold but does satisfy all these requirements: https://github.com/nikomatsakis/typed-objects-explainer/blob/master/valuetypes.md#the-typeof-operator Additionally, there is already a system for coordinating tags across module systems and even realms in ES6. Namely using `Symbol.for`. Currently these objects are not able to transfer between Workers but there is nothing preventing that from being possible in the future. You could imagine even `Symbol.for` working across Worker boundaries. You could also build a system that coordinates Symbols and Value Types from server to client or through serialized forms. That's beyond the scope of React itself, and if it was built it seems like it would belong with the `Symbol` system. A system could override the `Symbol.for('react.element')` to return a plain yet cryptographically random or unique number. That would allow ReactElements to pass through JSON without risking the XSS issue. The fallback solution is a plain well-known number. This makes it unsafe with regard to the XSS issue described in #3473. We could have used a much more convoluted solution to protect against JSON specifically but that would require some kind of significant coordination, or change the check to do a `typeof element.$$typeof === 'function'` check which would not make it unique to React. It seems cleaner to just use a fixed number since the protection is just a secondary layer anyway. I'm not sure if this is the right tradeoff. In short, if you want the XSS protection, use a proper Symbol polyfill. Finally, the reason for calling it `$$typeof` is to avoid confusion with `.type` and the use case is to add a tag that the `typeof` operator would refer to. I would use `@@typeof` but that seems to deopt in JSC. I also don't use `__typeof` because this is more than a framework private. It should really be part of the polyfilling layer.
2015-09-10 14:19:00 +08:00
var newElement = ReactElement(
2015-04-11 15:55:58 +08:00
oldElement.type,
newKey,
oldElement.ref,
Use a Symbol to tag every ReactElement Fixes #3473 I tag each React element with `$$typeof: Symbol.for('react.element')`. We need this to be able to safely distinguish these from plain objects that might have come from user provided JSON. The idiomatic JavaScript way of tagging an object is for it to inherent some prototype and then use `instanceof` to test for it. However, this has limitations since it doesn't work with value types which require `typeof` checks. They also don't work across realms. Which is why there are alternative tag checks like `Array.isArray` or the `toStringTag`. Another problem is that different instances of React that might have been created not knowing about eachother. npm tends to make this kind of problem occur a lot. Additionally, it is our hope that ReactElement will one day be specified in terms of a "Value Type" style record instead of a plain Object. This Value Types proposal by @nikomatsakis is currently on hold but does satisfy all these requirements: https://github.com/nikomatsakis/typed-objects-explainer/blob/master/valuetypes.md#the-typeof-operator Additionally, there is already a system for coordinating tags across module systems and even realms in ES6. Namely using `Symbol.for`. Currently these objects are not able to transfer between Workers but there is nothing preventing that from being possible in the future. You could imagine even `Symbol.for` working across Worker boundaries. You could also build a system that coordinates Symbols and Value Types from server to client or through serialized forms. That's beyond the scope of React itself, and if it was built it seems like it would belong with the `Symbol` system. A system could override the `Symbol.for('react.element')` to return a plain yet cryptographically random or unique number. That would allow ReactElements to pass through JSON without risking the XSS issue. The fallback solution is a plain well-known number. This makes it unsafe with regard to the XSS issue described in #3473. We could have used a much more convoluted solution to protect against JSON specifically but that would require some kind of significant coordination, or change the check to do a `typeof element.$$typeof === 'function'` check which would not make it unique to React. It seems cleaner to just use a fixed number since the protection is just a secondary layer anyway. I'm not sure if this is the right tradeoff. In short, if you want the XSS protection, use a proper Symbol polyfill. Finally, the reason for calling it `$$typeof` is to avoid confusion with `.type` and the use case is to add a tag that the `typeof` operator would refer to. I would use `@@typeof` but that seems to deopt in JSC. I also don't use `__typeof` because this is more than a framework private. It should really be part of the polyfilling layer.
2015-09-10 14:19:00 +08:00
oldElement._self,
oldElement._source,
2015-04-11 15:55:58 +08:00
oldElement._owner,
oldElement.props
);
return newElement;
};
ReactElement.cloneElement = function(element, config, children) {
var propName;
// Original props are copied
var props = assign({}, element.props);
// Reserved names are extracted
var key = element.key;
var ref = element.ref;
Use a Symbol to tag every ReactElement Fixes #3473 I tag each React element with `$$typeof: Symbol.for('react.element')`. We need this to be able to safely distinguish these from plain objects that might have come from user provided JSON. The idiomatic JavaScript way of tagging an object is for it to inherent some prototype and then use `instanceof` to test for it. However, this has limitations since it doesn't work with value types which require `typeof` checks. They also don't work across realms. Which is why there are alternative tag checks like `Array.isArray` or the `toStringTag`. Another problem is that different instances of React that might have been created not knowing about eachother. npm tends to make this kind of problem occur a lot. Additionally, it is our hope that ReactElement will one day be specified in terms of a "Value Type" style record instead of a plain Object. This Value Types proposal by @nikomatsakis is currently on hold but does satisfy all these requirements: https://github.com/nikomatsakis/typed-objects-explainer/blob/master/valuetypes.md#the-typeof-operator Additionally, there is already a system for coordinating tags across module systems and even realms in ES6. Namely using `Symbol.for`. Currently these objects are not able to transfer between Workers but there is nothing preventing that from being possible in the future. You could imagine even `Symbol.for` working across Worker boundaries. You could also build a system that coordinates Symbols and Value Types from server to client or through serialized forms. That's beyond the scope of React itself, and if it was built it seems like it would belong with the `Symbol` system. A system could override the `Symbol.for('react.element')` to return a plain yet cryptographically random or unique number. That would allow ReactElements to pass through JSON without risking the XSS issue. The fallback solution is a plain well-known number. This makes it unsafe with regard to the XSS issue described in #3473. We could have used a much more convoluted solution to protect against JSON specifically but that would require some kind of significant coordination, or change the check to do a `typeof element.$$typeof === 'function'` check which would not make it unique to React. It seems cleaner to just use a fixed number since the protection is just a secondary layer anyway. I'm not sure if this is the right tradeoff. In short, if you want the XSS protection, use a proper Symbol polyfill. Finally, the reason for calling it `$$typeof` is to avoid confusion with `.type` and the use case is to add a tag that the `typeof` operator would refer to. I would use `@@typeof` but that seems to deopt in JSC. I also don't use `__typeof` because this is more than a framework private. It should really be part of the polyfilling layer.
2015-09-10 14:19:00 +08:00
// Self is preserved since the owner is preserved.
var self = element._self;
// Source is preserved since cloneElement is unlikely to be targeted by a
// transpiler, and the original source is probably a better indicator of the
// true owner.
var source = element._source;
// Owner will be preserved, unless ref is overridden
var owner = element._owner;
if (config != null) {
if (config.ref !== undefined) {
// Silently steal the ref from the parent.
ref = config.ref;
owner = ReactCurrentOwner.current;
}
if (config.key !== undefined) {
key = '' + config.key;
}
// Remaining properties override existing props
var defaultProps;
if (element.type && element.type.defaultProps) {
defaultProps = element.type.defaultProps;
}
for (propName in config) {
if (config.hasOwnProperty(propName) &&
!RESERVED_PROPS.hasOwnProperty(propName)) {
if (config[propName] === undefined && defaultProps !== undefined) {
// Resolve default props
props[propName] = defaultProps[propName];
} else {
props[propName] = config[propName];
}
}
}
}
// Children can be more than one argument, and those are transferred onto
// the newly allocated props object.
var childrenLength = arguments.length - 2;
if (childrenLength === 1) {
props.children = children;
} else if (childrenLength > 1) {
var childArray = Array(childrenLength);
for (var i = 0; i < childrenLength; i++) {
childArray[i] = arguments[i + 2];
}
props.children = childArray;
}
return ReactElement(
element.type,
key,
ref,
self,
source,
owner,
props
);
};
/**
* @param {?object} object
* @return {boolean} True if `object` is a valid component.
* @final
*/
ReactElement.isValidElement = function(object) {
Use a Symbol to tag every ReactElement Fixes #3473 I tag each React element with `$$typeof: Symbol.for('react.element')`. We need this to be able to safely distinguish these from plain objects that might have come from user provided JSON. The idiomatic JavaScript way of tagging an object is for it to inherent some prototype and then use `instanceof` to test for it. However, this has limitations since it doesn't work with value types which require `typeof` checks. They also don't work across realms. Which is why there are alternative tag checks like `Array.isArray` or the `toStringTag`. Another problem is that different instances of React that might have been created not knowing about eachother. npm tends to make this kind of problem occur a lot. Additionally, it is our hope that ReactElement will one day be specified in terms of a "Value Type" style record instead of a plain Object. This Value Types proposal by @nikomatsakis is currently on hold but does satisfy all these requirements: https://github.com/nikomatsakis/typed-objects-explainer/blob/master/valuetypes.md#the-typeof-operator Additionally, there is already a system for coordinating tags across module systems and even realms in ES6. Namely using `Symbol.for`. Currently these objects are not able to transfer between Workers but there is nothing preventing that from being possible in the future. You could imagine even `Symbol.for` working across Worker boundaries. You could also build a system that coordinates Symbols and Value Types from server to client or through serialized forms. That's beyond the scope of React itself, and if it was built it seems like it would belong with the `Symbol` system. A system could override the `Symbol.for('react.element')` to return a plain yet cryptographically random or unique number. That would allow ReactElements to pass through JSON without risking the XSS issue. The fallback solution is a plain well-known number. This makes it unsafe with regard to the XSS issue described in #3473. We could have used a much more convoluted solution to protect against JSON specifically but that would require some kind of significant coordination, or change the check to do a `typeof element.$$typeof === 'function'` check which would not make it unique to React. It seems cleaner to just use a fixed number since the protection is just a secondary layer anyway. I'm not sure if this is the right tradeoff. In short, if you want the XSS protection, use a proper Symbol polyfill. Finally, the reason for calling it `$$typeof` is to avoid confusion with `.type` and the use case is to add a tag that the `typeof` operator would refer to. I would use `@@typeof` but that seems to deopt in JSC. I also don't use `__typeof` because this is more than a framework private. It should really be part of the polyfilling layer.
2015-09-10 14:19:00 +08:00
return (
typeof object === 'object' &&
Use a Symbol to tag every ReactElement Fixes #3473 I tag each React element with `$$typeof: Symbol.for('react.element')`. We need this to be able to safely distinguish these from plain objects that might have come from user provided JSON. The idiomatic JavaScript way of tagging an object is for it to inherent some prototype and then use `instanceof` to test for it. However, this has limitations since it doesn't work with value types which require `typeof` checks. They also don't work across realms. Which is why there are alternative tag checks like `Array.isArray` or the `toStringTag`. Another problem is that different instances of React that might have been created not knowing about eachother. npm tends to make this kind of problem occur a lot. Additionally, it is our hope that ReactElement will one day be specified in terms of a "Value Type" style record instead of a plain Object. This Value Types proposal by @nikomatsakis is currently on hold but does satisfy all these requirements: https://github.com/nikomatsakis/typed-objects-explainer/blob/master/valuetypes.md#the-typeof-operator Additionally, there is already a system for coordinating tags across module systems and even realms in ES6. Namely using `Symbol.for`. Currently these objects are not able to transfer between Workers but there is nothing preventing that from being possible in the future. You could imagine even `Symbol.for` working across Worker boundaries. You could also build a system that coordinates Symbols and Value Types from server to client or through serialized forms. That's beyond the scope of React itself, and if it was built it seems like it would belong with the `Symbol` system. A system could override the `Symbol.for('react.element')` to return a plain yet cryptographically random or unique number. That would allow ReactElements to pass through JSON without risking the XSS issue. The fallback solution is a plain well-known number. This makes it unsafe with regard to the XSS issue described in #3473. We could have used a much more convoluted solution to protect against JSON specifically but that would require some kind of significant coordination, or change the check to do a `typeof element.$$typeof === 'function'` check which would not make it unique to React. It seems cleaner to just use a fixed number since the protection is just a secondary layer anyway. I'm not sure if this is the right tradeoff. In short, if you want the XSS protection, use a proper Symbol polyfill. Finally, the reason for calling it `$$typeof` is to avoid confusion with `.type` and the use case is to add a tag that the `typeof` operator would refer to. I would use `@@typeof` but that seems to deopt in JSC. I also don't use `__typeof` because this is more than a framework private. It should really be part of the polyfilling layer.
2015-09-10 14:19:00 +08:00
object !== null &&
object.$$typeof === REACT_ELEMENT_TYPE
);
};
module.exports = ReactElement;