React: "this" undefined inside a component function

class PlayerControls extends React.Component { constructor(props) { super(props) this.state = { loopActive: false, shuffleActive: false, } } render() { var shuffleClassName = this.state.toggleActive ? "player-control-icon active" : "player-control-icon" return ( <div className="player-controls"> <FontAwesome className="player-control-icon" name='refresh' onClick={this.onToggleLoop} spin={this.state.loopActive} /> <FontAwesome className={shuffleClassName} name='random' onClick={this.onToggleShuffle} /> </div> ); } onToggleLoop(event) { // "this is undefined??" <--- here this.setState({loopActive: !this.state.loopActive}) this.props.onToggleLoop() } 

I want to update the loopActive state when switching, but this object is undefined in the handler. According to the training document, I this should refer to a component. Did I miss something?

+112
this reactjs
Nov 28 '15 at 16:30
source share
7 answers

ES6 React.Component does not automatically bind methods to itself. You must link them yourself in the constructor. Like this:

 constructor (props){ super(props); this.state = { loopActive: false, shuffleActive: false, }; this.onToggleLoop = this.onToggleLoop.bind(this); } 
+171
Nov 28 '15 at 16:40
source share

There are several ways.

One of them is to add this.onToggleLoop = this.onToggleLoop.bind(this); in the constructor.

Another arrow function is onToggleLoop = (event) => {...} .

And then there is onClick={this.onToggleLoop.bind(this)} .

+75
Nov 28 '15 at 16:38
source share

Write your function as follows:

 onToggleLoop = (event) => { this.setState({loopActive: !this.state.loopActive}) this.props.onToggleLoop() } 

Fat Arrow Features

the binding for the this keyword is the same outside and inside the bold arrow function. This is different from functions declared with a function that can associate this with another object when called. Maintaining this binding is very convenient for operations such as matching: this.items.map (x => this.doSomethingWith (x)).

+17
Dec 04 '17 at 11:15
source share

I came across a similar binding in the rendering function and ended up passing the this context as follows:

 {someList.map(function(listItem) { // your code }, this)} 

I also used:

 {someList.map((listItem, index) => <div onClick={this.someFunction.bind(this, listItem)} /> )} 
+10
Jun 23 '16 at 23:09
source share

If you use babel, you bind this using the ES7 binding operator https://babeljs.io/docs/en/babel-plugin-transform-function-bind#auto-self-binding

 export default class SignupPage extends React.Component { constructor(props) { super(props); } handleSubmit(e) { e.preventDefault(); const data = { email: this.refs.email.value, } } render() { const {errors} = this.props; return ( <div className="view-container registrations new"> <main> <form id="sign_up_form" onSubmit={::this.handleSubmit}> <div className="field"> <input ref="email" id="user_email" type="email" placeholder="Email" /> </div> <div className="field"> <input ref="password" id="user_password" type="new-password" placeholder="Password" /> </div> <button type="submit">Sign up</button> </form> </main> </div> ) } } 
+1
Mar 14 '19 at 10:11
source share

You should notice that this depends on how the function is called. That is: when the function is called as a method of an object, its this set to the object to which the method is called.

this is available in the JSX context as a component object, so you can call the desired method with the built-in this method.

If you just pass the link to the function / method, it seems that the reaction will call it as an independent function.

 onClick={this.onToggleLoop} // Here you just passing reference, React will invoke it as independent function and this will be undefined onClick={()=>this.onToggleLoop()} // Here you invoking your desired function as method of this, and this in that function will be set to object from that function is called ie: your component object 
+1
Sep 05 '19 at 18:09
source share

If you call your created method in lifecycle methods like componentDidMount ... then you can only use this.onToggleLoop = this.onToogleLoop.bind(this) and the fat arrow function onToggleLoop = (event) => {...} .

The normal approach of declaring a function in a constructor does not work, because lifecycle methods are called earlier.

0
Sep 15 '17 at 7:41
source share



All Articles