<p dir="auto">Applying an invalid style will use property from previous render. This can cause some hard to pin down bugs since you may inadvertently be applying invalid styles but not notice because the style on the previous render was fine. But then rendering later on with the same props/state will cause a different style to be applied, because of what happened on the previous render.</p>
<p dir="auto">React version: 17.0.2</p>
<h2 dir="auto">Steps To Reproduce</h2>
<ol dir="auto">
<li>Apply a valid style property to a component (e.g <code class="notranslate">backgroundColor: red</code>)</li>
<li>Apply an invalid style property to a component (for example: <code class="notranslate">backgroundColor: 5</code>)</li>
<li>note: Background stays red</li>
<li>Change state to apply a valid style (or no style) (e.g <code class="notranslate">backgroundColor: white</code>)</li>
<li>note: background is now white</li>
<li>Change state to apply an invalid style again</li>
<li>Note that the background stays white, even though it has the same props as step 2 when it rendered red</li>
</ol>
<p dir="auto">Link to code example:</p>
<p dir="auto"><a href="https://codesandbox.io/s/frosty-water-hwbj6" rel="nofollow">https://codesandbox.io/s/frosty-water-hwbj6</a><br>
Click change then clear then change again to see it in action.</p>
<h2 dir="auto">The current behaviour</h2>
<ul dir="auto">
<li>When a style object property is invalid, it applies style property from the previous render</li>
</ul>
<h2 dir="auto">The expected behaviour</h2>
<p dir="auto">I think the sensible thing to do would be:</p>
<ul dir="auto">
<li>Display a warning in development mode if a property is invalid</li>
<li>Remove any the previous style property from the element if the property passed is invalid.</li>
</ul>
<p dir="auto">However I think as long as it does the same thing regardless of props passed in the previous render it is acceptable.</p>
<p dir="auto">Consider, for example, a relatively generic <code class="notranslate">&lt;Field /&gt;</code> component:</p>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="var fieldCounter = 0;

var Field = React.createClass({
    getInitialState: function() {
        return { inputId: 'field-' + ++fieldCounter };
    },
    render: function() {
        var props = this.props,
            inputId = this.state.inputId;

        return (
            &lt;div className='field'&gt;
                &lt;label htmlFor={inputId}&gt;{props.label}&lt;/label&gt;
                &lt;input type={props.type} id={inputId} name={props.name} value='' /&gt;
            &lt;/div&gt;
        );
    }
});"><pre class="notranslate"><span class="pl-k">var</span> <span class="pl-s1">fieldCounter</span> <span class="pl-c1">=</span> <span class="pl-c1">0</span><span class="pl-kos">;</span>

<span class="pl-k">var</span> <span class="pl-v">Field</span> <span class="pl-c1">=</span> <span class="pl-v">React</span><span class="pl-kos">.</span><span class="pl-en">createClass</span><span class="pl-kos">(</span><span class="pl-kos">{</span>
    <span class="pl-en">getInitialState</span>: <span class="pl-k">function</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
        <span class="pl-k">return</span> <span class="pl-kos">{</span> <span class="pl-c1">inputId</span>: <span class="pl-s">'field-'</span> <span class="pl-c1">+</span> <span class="pl-c1">++</span><span class="pl-s1">fieldCounter</span> <span class="pl-kos">}</span><span class="pl-kos">;</span>
    <span class="pl-kos">}</span><span class="pl-kos">,</span>
    <span class="pl-en">render</span>: <span class="pl-k">function</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
        <span class="pl-k">var</span> <span class="pl-s1">props</span> <span class="pl-c1">=</span> <span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">props</span><span class="pl-kos">,</span>
            <span class="pl-s1">inputId</span> <span class="pl-c1">=</span> <span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">state</span><span class="pl-kos">.</span><span class="pl-c1">inputId</span><span class="pl-kos">;</span>

        <span class="pl-k">return</span> <span class="pl-kos">(</span>
            <span class="pl-c1">&lt;</span><span class="pl-ent">div</span> <span class="pl-c1">className</span><span class="pl-c1">=</span><span class="pl-s">'field'</span><span class="pl-c1">&gt;</span>
                <span class="pl-c1">&lt;</span><span class="pl-ent">label</span> <span class="pl-c1">htmlFor</span><span class="pl-c1">=</span><span class="pl-kos">{</span><span class="pl-s1">inputId</span><span class="pl-kos">}</span><span class="pl-c1">&gt;</span><span class="pl-kos">{</span><span class="pl-s1">props</span><span class="pl-kos">.</span><span class="pl-c1">label</span><span class="pl-kos">}</span><span class="pl-c1">&lt;</span><span class="pl-c1">/</span><span class="pl-ent">label</span><span class="pl-c1">&gt;</span>
                <span class="pl-c1">&lt;</span><span class="pl-ent">input</span> <span class="pl-c1">type</span><span class="pl-c1">=</span><span class="pl-kos">{</span><span class="pl-s1">props</span><span class="pl-kos">.</span><span class="pl-c1">type</span><span class="pl-kos">}</span> <span class="pl-c1">id</span><span class="pl-c1">=</span><span class="pl-kos">{</span><span class="pl-s1">inputId</span><span class="pl-kos">}</span> <span class="pl-c1">name</span><span class="pl-c1">=</span><span class="pl-kos">{</span><span class="pl-s1">props</span><span class="pl-kos">.</span><span class="pl-c1">name</span><span class="pl-kos">}</span> <span class="pl-c1">value</span><span class="pl-c1">=</span><span class="pl-s">''</span> <span class="pl-c1">/</span><span class="pl-c1">&gt;</span>
            <span class="pl-c1">&lt;</span><span class="pl-c1">/</span><span class="pl-ent">div</span><span class="pl-c1">&gt;</span>
        <span class="pl-kos">)</span><span class="pl-kos">;</span>
    <span class="pl-kos">}</span>
<span class="pl-kos">}</span><span class="pl-kos">)</span><span class="pl-kos">;</span></pre></div>
<p dir="auto">In order for the <code class="notranslate">&lt;label /&gt;</code> tag to be semantically related to the <code class="notranslate">&lt;input /&gt;</code> tag, we obviously need to match the <code class="notranslate">for</code> attribute to the <code class="notranslate">&lt;input /&gt;</code> tag's <code class="notranslate">id</code> attribute.  Outside of that requirement, however, we have no need of the <code class="notranslate">id</code> attribute, so a solution like the one above is convenient as it handles that all internally, with no need for a consuming component to pass in an actual <code class="notranslate">id</code> value.</p>
<p dir="auto">The problem I'm running into, however, is that this causes the <code class="notranslate">id</code> attributes generated client-side to mismatch what was sent down by the server (the client-side <code class="notranslate">fieldCounter</code> restarts at <code class="notranslate">0</code> on every load, whereas the server-side reference obviously just keeps growing).</p>
<p dir="auto">This mismatch then results in an error being thrown:</p>
<p dir="auto"><code class="notranslate">Invariant Violation: You're trying to render a component to the document using server rendering [...]</code></p>
<p dir="auto">So, my question is this: am I overlooking an obvious solution here? I would <em>like</em> for the <code class="notranslate">&lt;Field /&gt;</code> component to be able to simply internalize the <code class="notranslate">id</code> generation as an implementation detail, but I can't seem to come up with a good mechanism for then matching up that id generation client-side.</p>
<p dir="auto">Thanks in advance!</p>