Skip to content

Commit ab9ff6d

Browse files
committed
Make ReactElement really a plain object
This should guarantee that the hidden class is the same after inlining.
1 parent 88042b1 commit ab9ff6d

File tree

2 files changed

+29
-87
lines changed

2 files changed

+29
-87
lines changed

src/isomorphic/classic/element/ReactElement.js

Lines changed: 26 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -14,66 +14,17 @@
1414
var ReactCurrentOwner = require('ReactCurrentOwner');
1515

1616
var assign = require('Object.assign');
17-
var warning = require('warning');
1817

1918
var RESERVED_PROPS = {
2019
key: true,
2120
ref: true,
2221
};
2322

24-
/**
25-
* Warn for mutations.
26-
*
27-
* @internal
28-
* @param {object} object
29-
* @param {string} key
30-
*/
31-
function defineWarningProperty(object, key) {
32-
Object.defineProperty(object, key, {
33-
34-
configurable: false,
35-
enumerable: true,
36-
37-
get: function() {
38-
if (!this._store) {
39-
return null;
40-
}
41-
return this._store[key];
42-
},
43-
44-
set: function(value) {
45-
warning(
46-
false,
47-
'Don\'t set the %s property of the React element. Instead, ' +
48-
'specify the correct value when initially creating the element.',
49-
key
50-
);
51-
this._store[key] = value;
52-
},
53-
54-
});
55-
}
56-
57-
/**
58-
* This is updated to true if the membrane is successfully created.
59-
*/
60-
var useMutationMembrane = false;
61-
62-
/**
63-
* Warn for mutations.
64-
*
65-
* @internal
66-
* @param {object} element
67-
*/
68-
function defineMutationMembrane(prototype) {
23+
var canDefineProperty = false;
24+
if (__DEV__) {
6925
try {
70-
var pseudoFrozenProperties = {
71-
props: true,
72-
};
73-
for (var key in pseudoFrozenProperties) {
74-
defineWarningProperty(prototype, key);
75-
}
76-
useMutationMembrane = true;
26+
Object.defineProperty({}, 'x', {});
27+
canDefineProperty = true;
7728
} catch (x) {
7829
// IE will fail on defineProperty
7930
}
@@ -91,57 +42,46 @@ function defineMutationMembrane(prototype) {
9142
* @internal
9243
*/
9344
var ReactElement = function(type, key, ref, owner, props) {
94-
// Built-in properties that belong on the element
95-
this.type = type;
96-
this.key = key;
97-
this.ref = ref;
45+
var element = {
46+
// Built-in properties that belong on the element
47+
type: type,
48+
key: key,
49+
ref: ref,
9850

99-
// Record the component responsible for creating this element.
100-
this._owner = owner;
51+
// Record the component responsible for creating this element.
52+
_owner: owner,
53+
54+
props: props,
55+
56+
_isReactElement: true
57+
};
10158

10259
if (__DEV__) {
10360
// The validation flag and props are currently mutative. We put them on
10461
// an external backing store so that we can freeze the whole object.
10562
// This can be replaced with a WeakMap once they are implemented in
10663
// commonly used development environments.
107-
this._store = {props: props, originalProps: assign({}, props)};
64+
element._store = {originalProps: assign({}, props)};
10865

10966
// To make comparing ReactElements easier for testing purposes, we make
11067
// the validation flag non-enumerable (where possible, which should
11168
// include every environment we run tests in), so the test framework
11269
// ignores it.
113-
try {
114-
Object.defineProperty(this._store, 'validated', {
70+
if (canDefineProperty) {
71+
Object.defineProperty(element._store, 'validated', {
11572
configurable: false,
11673
enumerable: false,
11774
writable: true,
11875
});
119-
} catch (x) {
120-
}
121-
this._store.validated = false;
122-
123-
// We're not allowed to set props directly on the object so we early
124-
// return and rely on the prototype membrane to forward to the backing
125-
// store.
126-
if (useMutationMembrane) {
127-
Object.freeze(this);
128-
return;
12976
}
130-
}
77+
element._store.validated = false;
13178

132-
this.props = props;
133-
};
79+
Object.freeze(element);
80+
}
13481

135-
// We intentionally don't expose the function on the constructor property.
136-
// ReactElement should be indistinguishable from a plain object.
137-
ReactElement.prototype = {
138-
_isReactElement: true,
82+
return element;
13983
};
14084

141-
if (__DEV__) {
142-
defineMutationMembrane(ReactElement.prototype);
143-
}
144-
14585
ReactElement.createElement = function(type, config, children) {
14686
var propName;
14787

@@ -186,7 +126,7 @@ ReactElement.createElement = function(type, config, children) {
186126
}
187127
}
188128

189-
return new ReactElement(
129+
return ReactElement(
190130
type,
191131
key,
192132
ref,
@@ -207,7 +147,7 @@ ReactElement.createFactory = function(type) {
207147
};
208148

209149
ReactElement.cloneAndReplaceProps = function(oldElement, newProps) {
210-
var newElement = new ReactElement(
150+
var newElement = ReactElement(
211151
oldElement.type,
212152
oldElement.key,
213153
oldElement.ref,
@@ -266,7 +206,7 @@ ReactElement.cloneElement = function(element, config, children) {
266206
props.children = childArray;
267207
}
268208

269-
return new ReactElement(
209+
return ReactElement(
270210
element.type,
271211
key,
272212
ref,

src/isomorphic/classic/element/ReactElementValidator.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,9 @@ function validateChildKeys(node, parentType) {
206206
}
207207
} else if (ReactElement.isValidElement(node)) {
208208
// This element was passed in a valid location.
209-
node._store.validated = true;
209+
if (node._store) {
210+
node._store.validated = true;
211+
}
210212
} else if (node) {
211213
var iteratorFn = getIteratorFn(node);
212214
// Entry iterators provide implicit keys.

0 commit comments

Comments
 (0)