Reputation: 686
I'm currently in the process of learning React and I've come across something that seems weird in React's Getting Started guides.
I'm currently reading this section. There's this code sample: https://codepen.io/gaearon/pen/QKzAgB?editors=0011
It showcases conditional rendering, that's not the point of my question though. When they pass the HandleLogout/LoginEvent, they just pass this.HandleLoginEvent, without binding or using arrow functions, yet this code works perfectly, how does it work?
The piece of code I'm talking about is this:
let button = null;
if (isLoggedIn) {
button = <LogoutButton onClick={this.handleLogoutClick} />;
} else {
button = <LoginButton onClick={this.handleLoginClick} />;
}
In the previous section of the guides they explicitly state you have to use some method to bind the "this" in order for "this" not to be undefined when called from a child component, which makes sense.
Yet here "this" is somehow magically bound, how is it done?
Thanks, Avi.
EDIT: As Ori kindly pointed out, there's a bind call I've missed, problem solved :)
Upvotes: 0
Views: 1336
Reputation: 3451
There are multiple ways to handle React binding pattern:
render() {
return (
<LogoutButton onClick={::this.handleLogoutClick} />
{/* or */}
<LogoutButton onClick={this.handleLogoutClick.bind(this)} />
)
}
As shown in the codepen, which explains why you don't see binding in render
.
constructor(props) {
super(props)
this.handleLoginClick = this.handleLoginClick.bind(this)
// or
this.handleLoginClick = ::this.handleLoginClick
}
When you use arrow function to declare handleLogoutClick
, the function uses lexical binding.
Normally in JS, the value of this
is determined by how a function is called. But with ES6 arrow function, we are able to create function that behaves differently -
it retains the this
value of the enclosing lexical context, now we don't even have to call bind
!
handleLogoutClick = () => {
this.setState({isLoggedIn: false});
}
// and you can simply
onClick={this.handleLogoutClick}
Personally I definitely prefer arrow function, as it produces cleaner code, and I don't have to write that constructor just to bind stuffs. I can simply do:
class LoginControl extends React.Component {
state = {isLoggedIn: false}
//... other stuffs ...
}
As for binding in render (or arrow function inside render), you should always avoid that.
When working with PureComponent
, binding in render
will cause unnecessary re-rendering.
Why Arrow Functions and bind in React’s Render are Problematic
Upvotes: 4
Reputation: 3190
constructor(props) {
super(props);
this.handleLoginClick = this.handleLoginClick.bind(this);
this.handleLogoutClick = this.handleLogoutClick.bind(this);
this.state = {isLoggedIn: false};
}
When you do it this way you avoid forgetting to bind them when passing them all over the place.
Upvotes: 1