From 9faf1f39698463cd5220e58a5d325c8e2c006997 Mon Sep 17 00:00:00 2001 From: Ben Alpert Date: Tue, 22 Sep 2015 16:11:06 -0700 Subject: [PATCH] Improve error for style mutation Fixes #4877. I opted not to change shallowEqual for this since it seems relatively one-off. --- src/renderers/dom/shared/ReactDOMComponent.js | 30 +++++++++++++++++-- .../__tests__/ReactDOMComponent-test.js | 21 +++++++++++-- 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/src/renderers/dom/shared/ReactDOMComponent.js b/src/renderers/dom/shared/ReactDOMComponent.js index 07a313d9ec..47b164e9aa 100644 --- a/src/renderers/dom/shared/ReactDOMComponent.js +++ b/src/renderers/dom/shared/ReactDOMComponent.js @@ -170,6 +170,32 @@ function legacyReplaceProps(partialProps, callback) { } } +function friendlyStringify(obj) { + if (typeof obj === 'object') { + if (Array.isArray(obj)) { + return '[' + obj.map(friendlyStringify).join(', ') + ']'; + } else { + var pairs = []; + for (var key in obj) { + if (Object.prototype.hasOwnProperty.call(obj, key)) { + var keyEscaped = /^[a-z$_][\w$_]*$/i.test(key) ? + key : + JSON.stringify(key); + pairs.push(keyEscaped + ': ' + friendlyStringify(obj[key])); + } + } + return '{' + pairs.join(', ') + '}'; + } + } else if (typeof obj === 'string') { + return JSON.stringify(obj); + } else if (typeof obj === 'function') { + return '[function object]'; + } + // Differs from JSON.stringify in that undefined becauses undefined and that + // inf and nan don't become null + return String(obj); +} + var styleMutationWarning = {}; function checkAndWarnForMutatedStyle(style1, style2, component) { @@ -202,8 +228,8 @@ function checkAndWarnForMutatedStyle(style1, style2, component) { 'the `render` %s. Previous style: %s. Mutated style: %s.', componentName, owner ? 'of `' + ownerName + '`' : 'using <' + componentName + '>', - JSON.stringify(style1), - JSON.stringify(style2) + friendlyStringify(style1), + friendlyStringify(style2) ); } diff --git a/src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js b/src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js index afabd5c8dc..22b10f663d 100644 --- a/src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js +++ b/src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js @@ -128,8 +128,8 @@ describe('ReactDOMComponent', function() { 'Warning: `div` was passed a style object that has previously been ' + 'mutated. Mutating `style` is deprecated. Consider cloning it ' + 'beforehand. Check the `render` of `App`. Previous style: ' + - '{"border":"1px solid black"}. Mutated style: ' + - '{"border":"1px solid black","position":"absolute"}.' + '{border: "1px solid black"}. Mutated style: ' + + '{border: "1px solid black", position: "absolute"}.' ); style = {background: 'red'}; @@ -147,6 +147,23 @@ describe('ReactDOMComponent', function() { expect(console.error.argsForCall.length).toBe(2); }); + it('should warn semi-nicely about NaN in style', function() { + spyOn(console, 'error'); + + var style = {fontSize: NaN}; + var div = document.createElement('div'); + ReactDOM.render(, div); + ReactDOM.render(, div); + + expect(console.error.argsForCall.length).toBe(1); + expect(console.error.argsForCall[0][0]).toEqual( + 'Warning: `span` was passed a style object that has previously been ' + + 'mutated. Mutating `style` is deprecated. Consider cloning it ' + + 'beforehand. Check the `render` using . Previous style: ' + + '{fontSize: NaN}. Mutated style: {fontSize: NaN}.' + ); + }); + it('should update styles if initially null', function() { var styles = null; var container = document.createElement('div');