1

If I have the following react component:

class Cmpt extends Component {
   setValue( e ) {
     this.setState({ value : e.target.value });
   }
   render() {
     return <input value={this.state.val} onChange={this.setValue.bind(this)}/>
   }
}

Now this works as expected, editing the text doesn't reset the cursor to the end of the input. If I modify it such that the setState happens in async, the cursor reset occurs:

class Cmpt extends Component {
   setValue( e ) {
     setTimeout( () =>
       this.setState({ value : e.target.value }) );
   }
   render() {
     return <input value={this.state.val} onChange={this.setValue.bind(this)}/>
   }
}

Obviously the fix is to not call setState synchronously - but I don't understand why the async version doesn't work properly. In my head, the chain of events is as follows:

  1. User adds a character to an input field, changing it from ACD to ABCD
  2. The value of the input DOM node is changed to ABCD to reflect this
  3. Some time passes
  4. setState is called - changing the state of the react component from ACD to ABCD
  5. a render call is triggered - the React diffing algorithm compares the DOM nodes value (ABCD) to the value of this.state.value (ABCD). It sees that both are the same and therefore doesn't trigger a redraw and the cursor is preserved

Clearly my mental model is wrong because a redraw is being triggered - causing the cursor reset.

Please can anyone explain why?

Thanks!

maambmb
  • 881
  • 1
  • 8
  • 18
  • 1
    Possible duplicate of [In ReactJS, why does \`setState\` behave differently when called synchronously?](http://stackoverflow.com/questions/28922275/in-reactjs-why-does-setstate-behave-differently-when-called-synchronously) – maambmb Apr 09 '17 at 12:30

2 Answers2

0

A state changes will always trigger a new render call. After that React itself decides on what to re-render. But it will always get triggered by changing the state. Even if you do

this.setState({})

it will call the render method.

Murat Karagöz
  • 35,401
  • 16
  • 78
  • 107
  • for sure, but my question was why React was choosing to re-render the text input (causing the cursor reset) when setState was called async vs sync – maambmb Apr 09 '17 at 12:14
0

Sorry guys, found a duplicate question that answers my question:

In ReactJS, why does `setState` behave differently when called synchronously?

I can't figure out how to mark my own question as a duplicate unfortunately :(

My mental model of the order of events is wrong. Apparently react triggers a synchronous re-render at the end of every event handler, so render is getting called after the DOM changes, but before the react state has changed - causing a redraw and a cursor reset

Thanks all

T

Community
  • 1
  • 1
maambmb
  • 881
  • 1
  • 8
  • 18