6

As I understand it, onFocus should be called when the input box is clicked into, and onBlur should be called when something else becomes the focus.

My intentions: I would like to call a function that, when activated by a click, it will .concat the message string of the input box in focuse, but I can't get the onFocus or onBlur to work.

From what I've found searching around, this should do the trick, but doesn't.

import React, { Component } from 'react'
class SocialPost extends Component {
    state = {
        message: this.props.socialPost.message,
        focus: false
    }
    _onBlur() {
        setTimeout(() => {
            if (this.state.focus) {
                this.setState({
                    focus: false,
                });
            }
        }, 0);
    }
    _onFocus() {
        if (!this.state.focus) {
            this.setState({
                focus: true,
            });
        }
    }
    render() {
        return (
            <div className='...'>
                <div className='...'>
                    ...
                    <input
                        onFocus={this._onFocus()}
                        onBlur={this._onBlur()}
                        type='text'
                        value={this.state.message}
                        onChange={...}/>
                    ...
                </div>
            </div>
        )
    }
}
export default SocialPost
  1. Why is onFocus and onBlur called when the component is rendered before I click/unclick them?
  2. How do I get this onFocus and onBlur to work, is is there another way to focus on the activated input box?
Kevin Danikowski
  • 4,620
  • 6
  • 41
  • 75
  • 1
    Why your state is not defined inside the `constructor` function? – Arup Rakshit Oct 23 '17 at 19:15
  • @ArupRakshit I have seen many examples without inside the constructor and read it was unnecessary. I've been having problems having it one way versus another, so I just left it like this. After adding `bind(this)` like all suggested, now `this.state` from where it is being called is undefined, I will add constructor and try to fix it this way – Kevin Danikowski Oct 23 '17 at 19:18
  • 1
    `this` has special meaning inside the constructor and outside the constructor. The way react use `state`, it needs to be inside the constructor when using ES2015 class. – Arup Rakshit Oct 23 '17 at 19:20

4 Answers4

12
  1. It is called because you run the function in the render method, you should pass function, not what they return.

Change this:

onFocus={this._onFocus()}
onBlur={this._onBlur()}

to this:

onFocus={this._onFocus}
onBlur={this._onBlur}

2.You cannot declare component's state like that. It has to be done in constructor. Also if you want to refer to SocialPost's this you have to bind it. Imo the best place to do it is in the constructor. The whole code should look like this:

import React, { Component } from 'react'
class SocialPost extends Component {
    constructor (props) {
      super(props)
      this.state = {
        message: props.socialPost.message,
        focus: false
      }

      this._onBlur = this._onBlur.bind(this)
      this._onFocus = this._onFocus.bind(this)
    }
    _onBlur() {
        setTimeout(() => {
            if (this.state.focus) {
                this.setState({
                    focus: false,
                });
            }
        }, 0);
    }
    _onFocus() {
        if (!this.state.focus) {
            this.setState({
                focus: true,
            });
        }
    }
    render() {
        return (
            <div className='...'>
                <div className='...'>
                    ...
                    <input
                        onFocus={this._onFocus}
                        onBlur={this._onBlur}
                        type='text'
                        value={this.state.message}
                        onChange={...}/>
                    ...
                </div>
            </div>
        )
    }
}
export default SocialPost
P. Zietal
  • 314
  • 3
  • 13
  • Thank you P Zietal, you solved my issue. Not only was I calling the function in correctly, but after setting state to use the constructor (didn't work at first) I wasn't binding the functions thereafter. I appreciate it! – Kevin Danikowski Oct 23 '17 at 19:28
  • This answer is also better than the others because we are binding in the constructor. If you are binding outside of the constructor, like some of the other answers, each time your component renders it must run that bind function again instead of just the once in the constructor. – user2465134 Oct 23 '17 at 20:03
  • Did not know about the binding. Thing is I was not using constructor method, cause i did not find it useful. However, constructor is needed if using binding (or state initialisation) according to React docs: https://reactjs.org/docs/react-component.html#constructor – lucasrodesg Apr 12 '20 at 15:34
  • Thanks for your answer - this helped me too after having this issue for a long time Appreciate it! – Murtaza JAFARI Oct 18 '20 at 11:22
  • all this time after using React, I still forget this, I even search for finding whats wrong with my code, never gets old, anyway thanks for the clean answer! – Hasintha Abeykoon Sep 22 '21 at 04:24
2

Change

onFocus={this._onFocus()}
onBlur={this._onBlur()}

to

onFocus={this._onFocus}
onBlur={this._onBlur}

or

onFocus={this._onFocus.bind(this)}
onBlur={this._onBlur.bind(this)}
Alexander Vitanov
  • 4,074
  • 2
  • 19
  • 22
1

You are executing the method here

<input
    onFocus={this._onFocus()}
    onBlur={this._onBlur()}
    type='text'
    value={this.state.message}
    onChange={...}/>

It should be without parenthesis.

<input
    onFocus={this._onFocus.bind(this)}
    onBlur={this._onBlur.bind(this)}
    type='text'
    value={this.state.message}
    onChange={...}/>

EDIT:

And add .bind(this)

Kenji Mukai
  • 599
  • 4
  • 8
  • 1
    `this` will not be pointing to the instance of the component. You need to `bind` it or use `=>` to access the `this`. – Arup Rakshit Oct 23 '17 at 19:14
1
<input onFocus={this._onFocus.bind(this)} onBlur={this._onBlur.bind(this)} />

that's how it should be if you want to use THIS in the function

Arup Rakshit
  • 116,827
  • 30
  • 260
  • 317
Ilya Novojilov
  • 871
  • 8
  • 12