React — to Bind or Not to Bind

When and why do we bind this to the React component method.

Luka Bracanovic
Shoutem
4 min readMar 10, 2017

--

Handling events in React components is the most common case to use binding. Before going any further, I recommend reading an article about this at MDN if you are uncertain how does this works.

Why do we bind “this” to the function?

To retain object instance when the function is going to be passed. Certainly, it must be semantically correct for the function to expect such object. Most common case is to bind this when passing object method. Remember:

This depends how the function is called, not how/where it is created.

This should be retained when used in the function. This is used for an internal matter, data which, is not dynamic, doesn’t depend on function caller, usually already defined when the function is passed away.

Lets dig in an example

React generic components, for example, Buttons, by their generic nature should not know anything about data model and application behavior. That being said, generic buttons should not have properties like id, value, etc and shouldn’t do any specific operation. Generic buttons are dumb, they are pressable, and that’s all.

Press handle entirely defines what is going to happen when the button is pressed. That handle has all needed information within itself or more specific this (or in scope). It is an internal matter of the handle; the button does not add any value to the action, except an event.

class ArticlesListScreen extends Component {
constructor(props, context) {
super(props, context);
// Binding "this" creates new function with explicitly defined "this"
// Now "openArticleDetailsScreen" has "ArticleListScreen" instance as "this"
// no matter how the method/function is called.
this.openArticleDetailsScreen = this.openArticleDetailsScreen.bind(this);
}
openArticleDetailsScreen() {
const { article } = this.props;
openArticleScreen(article.id);
}
renderArticle() {
return (
<View>
<Text> An Article! </Text>
<Button
{/*Passing method to the component as handle.*/}
onPress={this.openArticleDetailsScreen}
>
Open Details
</Button>
</View>
);
}
}
function Button({ onPress, children }) {
return (
<TouchableOpacity onPress={onPress}>
<Text>{children}</Text>
</TouchableOpacity>
);
}

What about a smart, specific button, for example, ArticleDetailsButton?
It is the same thing, but it is just different place where handle is defined. On the end, last component is always generic one.

class ArticlesListScreen extends Component {
getArticle(articleId) {
const { articles } = this.props;
return articles.find(article => article.id === articleId);
}
renderArticle(articleId) {
const { article } = this.props;
return (
<View>
<Text> What a great article! </Text>
{/*Calling method directly from "this", so no need for binding.*/}
<Button article={this.getArticle(articleId)} />
</View>
);
}
}
class ArticleDetailsButton extends Component {
constructor(props, context) {
super(props, context);
// It is the same thing, only difference is Component where we do the binding.
// Component is lower in the tree, and now button has the logic how to open the screen.
this.openArticleDetails = this.openArticleDetails.bind(this);
}
openArticleDetails() {
const { article } = this.props;
openArticleDetails(article.id);
}
render() {
return (
<TouchableOpacity onPress={this.openArticleDetails}>
<Text>Open Details</Text>
</TouchableOpacity>
);
}
}

Other binding cases

Event handles (callbacks in general) are not only case to bind of course, as mentioned before, if passed method refers to the this in any way, proper this must be retained. Another common case when method is passed is as comparator or iterator.

This is a very neat thing, it removes unnecessary wrappers as well as anonymous functions.

For example, imagine ArticleDetailsScreen connected to redux state with article and tags props. For the purpose of example, article will have multiple tag ids. Goal is to render article content with tags titles.

class ArticleDetailsScreen extends Component {
constructor(props, context) {
super(props, context);
this.renderTagComponent = this.renderTagComponent.bind(this);
}
renderTagComponent(tagId) {
const { tags } = this.props;
const tag = tags.find(tag => tag.id === tagId);
return <Text key={tagId}>{tag.title}</Text>;
}
render() {
const { article } = this.props;
// Nice, isn't it?
// Without anonymous function monster as argument :)
const articleTags = article.tags.map(this.renderTagComponent);
return (
<View>
<Text>{article.content}</Text>
{articleTags}
</View>
);
}
}

Arrow function to the rescue?

Arrow function should not be used in the component render method. Render is called repeatedly, thus arrow function create a new function often and unnecessary. Remember:

Bind creates a new function!

Finally, when to bind?

Depending on how a function is called or passed and whether it uses this or not you have to bind.

If the function is called on this, a method actually, then it has caller this.

By default, if the function is not called, but rather passed, then that function will have this depending on how it is called later, most likely undefined.

Bind “disclaimer”

Not to talk only “rainbows and unicorns”, even though bind is a very powerful tool it shouldn’t be abused. The bind adds complexity to the function because it hides a certain part of the context. It is much more cleaner for function to use only its own arguments. Function which bind any context isn’t pure, that is a big downside.

I work at Shoutem where I help creating tools to supercharge your React Native development.

--

--