Skip to content

Commit dad09c6

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

File tree

2 files changed

+29
-83
lines changed

2 files changed

+29
-83
lines changed

src/isomorphic/classic/element/ReactElement.js

Lines changed: 26 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -22,59 +22,14 @@ var RESERVED_PROPS = {
2222
ref: true
2323
};
2424

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

99-
// Record the component responsible for creating this element.
100-
this._owner = owner;
55+
// Record the component responsible for creating this element.
56+
_owner: owner,
57+
58+
props: props,
59+
60+
_isReactElement: true
61+
};
10162

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

10970
// To make comparing ReactElements easier for testing purposes, we make
11071
// the validation flag non-enumerable (where possible, which should
11172
// include every environment we run tests in), so the test framework
11273
// ignores it.
113-
try {
114-
Object.defineProperty(this._store, 'validated', {
74+
if (canDefineProperty) {
75+
Object.defineProperty(element._store, 'validated', {
11576
configurable: false,
11677
enumerable: false,
11778
writable: true
11879
});
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;
12980
}
130-
}
81+
element._store.validated = false;
13182

132-
this.props = props;
133-
};
83+
Object.freeze(element);
84+
}
13485

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
86+
return element;
13987
};
14088

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

@@ -186,7 +130,7 @@ ReactElement.createElement = function(type, config, children) {
186130
}
187131
}
188132

189-
return new ReactElement(
133+
return ReactElement(
190134
type,
191135
key,
192136
ref,
@@ -208,7 +152,7 @@ ReactElement.createFactory = function(type) {
208152
};
209153

210154
ReactElement.cloneAndReplaceProps = function(oldElement, newProps) {
211-
var newElement = new ReactElement(
155+
var newElement = ReactElement(
212156
oldElement.type,
213157
oldElement.key,
214158
oldElement.ref,
@@ -268,7 +212,7 @@ ReactElement.cloneElement = function(element, config, children) {
268212
props.children = childArray;
269213
}
270214

271-
return new ReactElement(
215+
return ReactElement(
272216
element.type,
273217
key,
274218
ref,

src/isomorphic/classic/element/ReactElementValidator.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,9 @@ function validateChildKeys(node, parentType) {
191191
}
192192
} else if (ReactElement.isValidElement(node)) {
193193
// This element was passed in a valid location.
194-
node._store.validated = true;
194+
if (node._store) {
195+
node._store.validated = true;
196+
}
195197
} else if (node) {
196198
var iteratorFn = getIteratorFn(node);
197199
// Entry iterators provide implicit keys.

0 commit comments

Comments
 (0)