So if I assign onFocus
callback to <input />
and then call method focus()
on actual element, react won't fire onFocus
event and related callback won't be called.
It's a problem of react, not DOM method focus()
, because with addEventListener('focus', fn)
it fire such an event.
Version is 15.3.2
UPDATE
I called this.refs.input.focus()
from componentWillReceiveProps
which do not support firing such an events by design I think.
Threw together a quick example: https://jsfiddle.net/TheSharpieOne/n78yc0jg/ It seems to be working fine.
If there is something else needed to get the result you are seeing, you should create your own example showcasing the issue.
Thanks for an example. I figured out the problem. I called this.refs.input.focus()
from componentWillReceiveProps
. To solve my issue I moved this call out of current stack by using setTimeout
.
What does this mean some one listening to my calls?
@Johnius, you didn't show any example so it is hard to evaluate your solution. setTimeout
in componentWillReceiveProps
looks like a hack. DOM operations (like focus()) are valid in componentDidMount
and componentDidUpdate
without setTimeout
.
Eventually I figured out what was the problem. I had two components: Container
and Input
. In first one I had a prop called lastTimeInputHasBeenFocused
set to a new Date()
. That prop was passed to a children element Input
. Inside Input
I have compared previous and next version of prop in lifecycle hook componentWillReceiveProps
and if it changed I called this.refs.input.focus()
.
The thing is you cannot focus input from either componentWillReceiveProps
or componentWillUpdate
when you are inside of a stack of <a />
's or <button />
's onClick
.
When props being propagated from <div />
's onClick
or when you still use <a />
or <button />
but lifecycle hook componentDidUpdate
— focusing this way works just fine.
Here's a fiddle for this case https://jsfiddle.net/n78yc0jg/3/
Greatly appreciated for documenting this, was pulling my hair out over why my input was not getting focus in componentWillReceivePorps()
!
Note: don’t use componentWillReceiveProps
for talking to the DOM. Use componentDidUpdate
.
I came across this issue when trying to figure out why accessing a ref I had in componentDidMount() to fire a .focus() event was not working-I was stumped because refs are one of the fundamental use cases for componentDidMount() (accessing the DOM). The reason is not the ref but .focus(). .focus() in particular has browser restrictions in some cases where the element is not entirely visible you are trying to focus() e.g animations.
For example, if you have any animations at all such as GSAP, .focus() events do not work when an element is invisible for security reasons (hackers could trick people into focusing a hidden text form). I had a GSAP transition that brought in the Mounted element that took 0.42 seconds (to the naked eye almost indistinguishable from being "visible". But, Setting a setTimeout that had the nameText.focus() to .42 seconds was the only way to get the .focus() event to work in componentDidMount().
@gaearon I'm wondering what's the motivation behind the restriction in regards to the tech side (except the conceptual collision).
@kmwarter Thank you! I was frustrated with this, finally! Could this be an improvement? Scenario is that, When animation starts to trigger with {visibilty: hidden}, after componentDidUpdate, or componentDidMount
The setTimeout worked for me too. But I call the focus in onClick event. Why does that behave like this?
Most helpful comment
I came across this issue when trying to figure out why accessing a ref I had in componentDidMount() to fire a .focus() event was not working-I was stumped because refs are one of the fundamental use cases for componentDidMount() (accessing the DOM). The reason is not the ref but .focus(). .focus() in particular has browser restrictions in some cases where the element is not entirely visible you are trying to focus() e.g animations.
For example, if you have any animations at all such as GSAP, .focus() events do not work when an element is invisible for security reasons (hackers could trick people into focusing a hidden text form). I had a GSAP transition that brought in the Mounted element that took 0.42 seconds (to the naked eye almost indistinguishable from being "visible". But, Setting a setTimeout that had the nameText.focus() to .42 seconds was the only way to get the .focus() event to work in componentDidMount().