4

with React state it was easy to set new value which was condition for render some input and then focus to that input with state callback.

handleToggleInput() {
  const showInput = !this.state.showInput
  this.setState({ showInput }, () => showInput && this.refs.input.focus())
}

render() {
  if(this.state.showInput) {
    <input ref="input" type="text />
  }
}

Now when switching to Mobx it is not possible

@observable showInput = false;

handleToggleInput() {
  this.showInput = !this.showInput
  this.showInput && this.refs.input.focus()
}

render() {
  if(this.showInput) {
    <input ref="input" type="text />
  }
}

This will fail, because React did not yet rerender component with input. Is there any way how wait and detect when rerender is done?

Schovi
  • 1,960
  • 5
  • 19
  • 33
  • Very interesting. It works if you [**defer the focus**](http://jsbin.com/kuzariquce/edit?js,output). If you don't conditionally hide the input, it works without the defer. Hopefully a MobX pro can shine some light on this. – Tholle Feb 26 '17 at 16:11
  • 1
    @Tholle Very clever! This probably works now fine, but in future with React Fiber or other React implementation can be problem because of rerender scheduling. – Schovi Feb 26 '17 at 23:29

1 Answers1

4

The callback in setState will run after the state is set and the component is re-rendered. MobX has no equivalent. So use this method to do the focus after React has re-rendered the UI.

componentDidUpdate: function(prevProps, prevState){
   this.refs.input.focus(); 
},

To run code immediately after first render

componentDidMount: function(){
   this.refs.input.focus(); 
},

React set focus on input after render

https://facebook.github.io/react/docs/react-component.html#componentdidupdate

Community
  • 1
  • 1
Jesvin Jose
  • 22,498
  • 32
  • 109
  • 202
  • Also start using the ref callback, as shown in the StackOverflow question. Using `ref="input"` is deprecated. – Jesvin Jose Feb 25 '17 at 11:22
  • 1
    But there I dont know the observable transition from "not show" to "show". ComponentDidUpdate can be triggered from million of other reasons. Only solution, but ugly one is to keep some property `this._focusOnUpdate = showInput` in handler and then reflect in it lifecycle event. But as I said it is ugly :( – Schovi Feb 25 '17 at 11:33
  • If you want a newly appearing input, why not use `autofocus` attribute for that input? – Jesvin Jose Feb 25 '17 at 13:51
  • Autofocus is neat and simple, but it became pretty complex when I `showInput` is true on first render, but I dont want to focus there. My initial question was more generic, how to react (in any way) to rerender after observable change. – Schovi Feb 25 '17 at 22:11