@samitouri / QOS-React-2 / commits / 9faf1f3969

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');