Search code examples
javascriptreactjsdeferred

Accent and deferred React's setState on input onChange


I'm creating a little utility where I need call a setState deferred to next tick fired by an input's onChange handler. Below a simple snippet showing the basic concept.

https://jsfiddle.net/samuelsimoes/q3p44sz1/

class MyComponent extends React.Component {
  constructor () {
    super(...arguments);
    this.state = {};
  }

  onChange (value) {
    setTimeout(v => {
      this.setState({ name: v });
    }.bind(this, value), 0);
  }

  render () {
    return (
      <div>
        <input
          type="text"
          value={this.state.name}
          onChange={evt => this.onChange(evt.target.value)} />
      </div>
    );
  }
};

ReactDOM.render(
  <MyComponent/>,
  document.getElementById("app-container")
);

If you run this snippet in a browser on Mac OS and try to type some letter with an accent you get an awkward behavior different on each browser. On Chrome the accent only works for the first time, after the accent isn't applied anymore (take a look on the gif below). On Firefox, the accent and letter don't appear.

Bug on Chrome

Do you guys have any clue about this?

p.s.: I tested this behavior on React 0.13, 0.14 and 15.0.2.


Solution

  • Basically you shouldn't defer the setState. React won't work properly in this situation.

    Look: https://github.com/facebook/react/issues/6563

    What is happening:

    Let's suppose that you press the letter A.

    1. When you trigger the onChange in the field, React processes all the state mutations.

    2. After the state mutation process, React does the DOM diff to update the component and at this stage the state value for this field is an empty value, so React does a node.value = "".

    3. On the next tick our deferred setState is triggered applying the letter A with the node.value = "A".

    This behavior breaks the browsers on MacOS where they replace the accent on the "intermediate state" to a typed accent preventing user to type the accentuated character.

    So, sadly there's no solution.