diff --git a/src/diff/props.js b/src/diff/props.js index ccad1fdccc4..caa189c970e 100644 --- a/src/diff/props.js +++ b/src/diff/props.js @@ -1,4 +1,4 @@ -import { IS_NON_DIMENSIONAL } from '../constants'; +import { IS_NON_DIMENSIONAL, EMPTY_OBJ } from '../constants'; import options from '../options'; /** @@ -27,7 +27,6 @@ export function diffProps(dom, newProps, oldProps, isSvg) { } } -const CAMEL_REG = /-?(?=[A-Z])/g; const XLINK_NS = 'http://www.w3.org/1999/xlink'; /** @@ -39,39 +38,28 @@ const XLINK_NS = 'http://www.w3.org/1999/xlink'; * @param {boolean} isSvg Whether or not this DOM node is an SVG node or not */ function setProperty(dom, name, value, oldValue, isSvg) { + let v; + name = isSvg ? (name==='className' ? 'class' : name) : (name==='class' ? 'className' : name); if (name==='style') { + // Always clear the previous styles + dom.style.cssText = EMPTY_OBJ; - /* Possible golfing activities for setting styles: - * - we could just drop String style values. They're not supported in other VDOM libs. - * - assigning to .style sets .style.cssText - TODO: benchmark this, might not be worth the bytes. - * - assigning also casts to String, and ignores invalid values. This means assigning an Object clears all styles. - */ - let s = dom.style; + for (let i in value) { + v = value[i]; + v = typeof v==='number' && IS_NON_DIMENSIONAL.test(i)===false ? (v + 'px') : v; - if (typeof value==='string') { - s.cssText = value; - } - else { - if (typeof oldValue==='string') s.cssText = ''; - else { - // remove values not in the new list - for (let i in oldValue) { - if (value==null || !(i in value)) s.setProperty(i.replace(CAMEL_REG, '-'), ''); - } + // For css vars, just define them with `setProperty`; + if (/^--/.test(i)) { + dom.style.setProperty(i, v); } - for (let i in value) { - const v = value[i]; - if (oldValue==null || v!==oldValue[i]) { - s.setProperty(i.replace(CAMEL_REG, '-'), typeof v==='number' && IS_NON_DIMENSIONAL.test(i)===false ? (v + 'px') : v); - } + else { + // Bench for setter vs (setProperty + regex) https://esbench.com/bench/5ccb5a284cd7e6009ef6232e + dom.style[i] = v; } } } - else if (name==='dangerouslySetInnerHTML') { - return; - } // Benchmark for comparison: https://esbench.com/bench/574c954bdb965b9a00965ac6 else if (name[0]==='o' && name[1]==='n') { let useCapture = name !== (name=name.replace(/Capture$/, '')); @@ -89,7 +77,7 @@ function setProperty(dom, name, value, oldValue, isSvg) { else if (name!=='list' && name!=='tagName' && !isSvg && (name in dom)) { dom[name] = value==null ? '' : value; } - else if (typeof value!=='function') { + else if (typeof value!=='function' && name != 'dangerouslySetInnerHTML') { if (name!==(name = name.replace(/^xlink:?/, ''))) { if (value==null || value===false) { dom.removeAttributeNS(XLINK_NS, name.toLowerCase()); diff --git a/test/browser/render.test.js b/test/browser/render.test.js index 49be953e49a..fe647c5c782 100644 --- a/test/browser/render.test.js +++ b/test/browser/render.test.js @@ -336,52 +336,6 @@ describe('render()', () => { }); describe('style attribute', () => { - it('should apply style as String', () => { - render(
, scratch); - expect(scratch.childNodes[0].style.cssText) - .to.equal('top: 5px; position: relative;'); - }); - - it('should not call CSSStyleDeclaration.setProperty for style strings', () => { - render(, scratch); - sinon.stub(scratch.firstChild.style, 'setProperty'); - render(, scratch); - expect(scratch.firstChild.style.setProperty).to.not.be.called; - }); - - it('should properly switch from string styles to object styles and back', () => { - render(( -