Improve error for style mutation
Fixes #4877. I opted not to change shallowEqual for this since it seems relatively one-off.
Ben Alpert committed
Sep 22, 2015 at 16:11 UTC
9faf1f39698463cd5220e58a5d325c8e2c006997
2 files changed
+47
-4
src/renderers/dom/shared/ReactDOMComponent.js
+28
-2
@@ -170,6 +170,32 @@ function legacyReplaceProps(partialProps, callback) {
170
}
171
}
172
173
+function friendlyStringify(obj) {
174
+ if (typeof obj === 'object') {
175
+ if (Array.isArray(obj)) {
176
+ return '[' + obj.map(friendlyStringify).join(', ') + ']';
177
+ } else {
178
+ var pairs = [];
179
+ for (var key in obj) {
180
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
181
+ var keyEscaped = /^[a-z$_][\w$_]*$/i.test(key) ?
182
+ key :
183
+ JSON.stringify(key);
184
+ pairs.push(keyEscaped + ': ' + friendlyStringify(obj[key]));
185
+ }
186
+ }
187
+ return '{' + pairs.join(', ') + '}';
188
+ }
189
+ } else if (typeof obj === 'string') {
190
+ return JSON.stringify(obj);
191
+ } else if (typeof obj === 'function') {
192
+ return '[function object]';
193
+ }
194
+ // Differs from JSON.stringify in that undefined becauses undefined and that
195
+ // inf and nan don't become null
196
+ return String(obj);
197
+}
198
+
199
var styleMutationWarning = {};
200
201
function checkAndWarnForMutatedStyle(style1, style2, component) {
@@ -202,8 +228,8 @@ function checkAndWarnForMutatedStyle(style1, style2, component) {
228
'the `render` %s. Previous style: %s. Mutated style: %s.',
229
componentName,
230
owner ? 'of `' + ownerName + '`' : 'using <' + componentName + '>',
205
- JSON.stringify(style1),
206
- JSON.stringify(style2)
231
+ friendlyStringify(style1),
232
+ friendlyStringify(style2)
233
);
234
}
235
src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js
+19
-2
@@ -128,8 +128,8 @@ describe('ReactDOMComponent', function() {
128
'Warning: `div` was passed a style object that has previously been ' +
129
'mutated. Mutating `style` is deprecated. Consider cloning it ' +
130
'beforehand. Check the `render` of `App`. Previous style: ' +
131
- '{"border":"1px solid black"}. Mutated style: ' +
132
- '{"border":"1px solid black","position":"absolute"}.'
131
+ '{border: "1px solid black"}. Mutated style: ' +
132
+ '{border: "1px solid black", position: "absolute"}.'
133
);
134
135
style = {background: 'red'};
@@ -147,6 +147,23 @@ describe('ReactDOMComponent', function() {
147
expect(console.error.argsForCall.length).toBe(2);
148
});
149
150
+ it('should warn semi-nicely about NaN in style', function() {
151
+ spyOn(console, 'error');
152
+
153
+ var style = {fontSize: NaN};
154
+ var div = document.createElement('div');
155
+ ReactDOM.render(<span style={style}></span>, div);
156
+ ReactDOM.render(<span style={style}></span>, div);
157
+
158
+ expect(console.error.argsForCall.length).toBe(1);
159
+ expect(console.error.argsForCall[0][0]).toEqual(
160
+ 'Warning: `span` was passed a style object that has previously been ' +
161
+ 'mutated. Mutating `style` is deprecated. Consider cloning it ' +
162
+ 'beforehand. Check the `render` using <span>. Previous style: ' +
163
+ '{fontSize: NaN}. Mutated style: {fontSize: NaN}.'
164
+ );
165
+ });
166
+
167
it('should update styles if initially null', function() {
168
var styles = null;
169
var container = document.createElement('div');