question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[10.0.0-alpha.2] Controlled form field rendered incorrectly after user input is "undone" via state

See original GitHub issue

I have implemented a somewhat “recalcitrant” form field, which in certain cases refuses to leave itself with the value a user set. This select group is fully “controlled” in that it uses selected/oninput rather than defaultSelected. This usually works except in one case:

If, after a user selects some other value, the value that I then render happens to be the value the group had before they selected, the user’s selection is left as-is.

E.g. say I have a select box with four options: none/red/green/blue. Whenever the user selects “none” I choose “blue” instead (bear with me; the paired select box code below is the real scenario):

  • If the box starts out “red” and the user selects “none”, the state and the box end up “blue”
  • If the box starts out “green” and the user selects “none”, the state and the box end up “blue”
  • But if the box starts out “blue” and the user selects “none”, the state ends up “blue” but the box stays as “none”!

I suspect something might be going wrong in the diffing, i.e. when the diffing sees that the new vdom value is the same as the old vdom value and it doesn’t bother to update? (There may be some irony in me complaining about this, since I celebrated what was perhaps this very behavior in the context of #1294 at least as far as unspecified props and/or mutated children went…)

Sample code

This code below has both a SingleSelect which demonstrates the issue above, as well as a DoubleSelect component to show the plausibility of why I would actually do this: when the user clears out the first of a pair of select boxes, if there is a remaining value (in the second box) it should move into the first. It works fine if the boxes have different values, but when they start out both the same, they end up both displaying “[none]” even though when the first has a value.

const SingleSelect = () => {
  const options = ['red', 'green', 'blue'];
  let [keyA, setKeyA] = useState(null);
  console.log("rendering:", keyA);
  
  return html`<div>
    <label>Color: </label>
    <select oninput=${evt => {
      let key = evt.target.value;
      if (key === '-') {
        setKeyA('blue');
      } else {
        setKeyA(key);
      }
    }}>
      <option value="-" selected=${!keyA}>[none]</option>
      ${options.map(key => html`<option value=${key} selected=${key === keyA}>${key}</option>`)}
    </select>
  </div>`
};

const DoubleSelect = () => {
  const options = ['red', 'green', 'blue'];
  let [keyA, setKeyA] = useState(null);
  let [keyB, setKeyB] = useState(null);
  console.log("rendering:", keyA, keyB);
  
  return html`<div>
    <label>Colors: </label>
    <select oninput=${evt => {
      let key = evt.target.value;
      if (key === '-') {
        setKeyA(keyB);
        setKeyB(null);
      } else {
        setKeyA(key);
      }
    }}>
      <option value="-" selected=${!keyA}>[none]</option>
      ${options.map(key => html`<option value=${key} selected=${key === keyA}>${key}</option>`)}
    </select>
    <select oninput=${evt => {
      let key = evt.target.value;
      setKeyB((key !== '-') ? key : null);
    }}>
      <option value="-" selected=${!keyB}>[none]</option>
      ${options.map(key => html`<option value=${key} selected=${key === keyB}>${key}</option>`)}
    </select>
  </div>`
};

render(html`
  <${DoubleSelect} />
  <${SingleSelect} />
`, document.body);

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:11 (10 by maintainers)

github_iconTop GitHub Comments

2reactions
mischniccommented, Mar 30, 2019

when the diffing sees that the new vdom value is the same as the old vdom value and it doesn’t bother to update

This might already be fixed with https://github.com/developit/preact/pull/1438 (I had a very similar issue: #1410)

1reaction
developitcommented, Apr 22, 2019

It seems like the issue here is actually the use of <option selected=..> instead of <select value=..>. Since Preact favors properties over attributes where they are defined, <select value=".."> is the preferred way of setting the value of a select.

Here’s a modified version of the repro sandbox showing correct functionality after being converted to use <select value>: https://codesandbox.io/s/jjkkr7xpjw

Read more comments on GitHub >

github_iconTop Results From Across the Web

In React ES6, why does the input field lose focus after typing a ...
Every time your state/prop change, the function returns a new form. it caused you to lose focus. Try putting what's inside the function...
Read more >
How to use React's controlled inputs for instant form field ...
Using controlled inputs implies we are storing all the input values in our state. We can then evaluate a particular condition with every ......
Read more >
Unity 5.4.0
This component allows using more than one light probe sample for large dynamic objects (think large particle systems or important characters).
Read more >
Unreal Engine 4.22 Release Notes
With this release, we're excited to announce Beta support for Ray Tracing and Path Tracing using Windows 10 RS5 update that takes full...
Read more >
Mattermost self-hosted changelog
Details will be posted on our security updates page 30 days after release as ... the user's full name was not shown when...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found