Should I be binding also inbuilt React methods? - javascript

It is a common practice to be bind a user-created method inside a React.Component class.
class App extends React.Component { // simplified example, not actual code
constructor(){
//...
this.logIn=this.logIn.bind(this) // Binding of a method
}
}
Naturally, this is beceause we need to explicitly bind the method to "this class", otherwise we would be referencing with this the window object!
What's however unclear to me, least from the documentation and so on I viewed, if we use in-built life-cycle methods such as render() or componentDidMount(), majority of the code snippets and also the official documentation seem to not explicitly bind to this
class App extends React.Component {
constructor(){
//....
this.componentDidMount = this.componentDidMount.bind(this)
// is there reason why we don't do this ^ ??
}
}
Is there some in-built binding already inside the React.Component we extend?
Or why don't we need to explicitly bind the life-cycle methods (componentDidMount()) like the rest of our created methods (logIn())?

I've made a component with the following:
...
componentDidMount() {
var that = this;
var x = 0;
}
...
render() {
....
<button onClick={this.componentDidMount}>DID MOUNT</button>
....
}
And the results are in -- when the function does initially mount, that is properly bound, but when clicked from the button, it is not.
Which means that the componentDidMount is not already bound, but it is called from the React internals with the proper context so that it doesn't need to be bound.
-- edit
Perhaps also of note: it's worth checking if you use an autobind package, if that binds the lifecycle methods. autobind-decorator in fact does!

Naturally, this is beceause we need to explicitly bind the method to "this class", otherwise we would be referencing with this the window object!
You can also use arrow functions to been able to use this without binding:
sayHello=()=>{
return 'hello';
}
myOtherFunction=()=>{
console.log('I can acces the other function! Say:'+ this.sayHello())
}
And you don't need to bind the life-cycle methods
Edit: As the documentation says in https://reactjs.org/docs/handling-events.html
You have to be careful about the meaning of this in JSX callbacks. In JavaScript, class methods are not bound by default. If you forget to bind this.handleClick and pass it to onClick, this will be undefined when the function is actually called.
So it is supposed that lifecycle methods are bound by default.

Related

Where should I bind methods in React component?

I learn React now and noticed that a lot of people bind their methods in constructor.
Like this:
class MyComponent extends React.Component {
constructor() {
super();
this.myMethod = this.myMethod.bind(this);
}
render() {
<button onClick={this.myMethod}>Click me</button>
}
myMethod() {
// do something
}
}
But I got used to writing something like this:
render() {
<button onClick={this.myMethod.bind(this)}>Click me</button>
}
And I was told by a couple of people that using the second method is a bad experience.
So could you tell me the differences between first and second methods? Any pros and cons? or performance issues?
You are right and what others told you is also right.
You are encouraged to do binding in constructor because constructor gets called only once per component so if you do binding in constructor it creates a new object/function only once in Webpack bundle.js file hence not much impact
You are not encouraged to do binding directly in render because a component renders for several reasons like when you do setState, when your component receives new props so your component will render so many times. So since you are binding directly in render whenever your component renders it will create a new function every time in Webpack bundle.js and your bundle file size will increase and that affects performance when your app contains thousands of components and if you do binding directly in render in every component.
So you are recommended to do binding only in constructor. Hope that clarifies
This results in creating a new bound function on every render call:
render() {
<button onClick={this.myMethod.bind(this)}>Click me</button>
}
Notice that if myMethod is used in multiple places, this requires multiple bind calls and may result in unbound callback if one of bind is missing.
While this creates bound function on component instantiation:
constructor() {
super();
this.myMethod = this.myMethod.bind(this);
}
The second option is recommended.
A decorator like autobind can be used to skip myMethod explicit assignment in constructor.
As explained in this answer, prototype methods with bind have less shortcomings than arrow instance methods and can be generally preferred.
You should bind in the constructor simply because the second way will create a new function every render.
But there's a better way to simply avoid binding. Use arrow function.
class MyComponent extends React.Component {
constructor() {
super();
}
render() {
<button onClick={this.myMethod}>Click me</button>
}
myMethod = ()=> {
// do something
}
}
Let's see how the creator of Redux Dan Abramov thinks about bind vs arrow functions -
Question:
In terms of performance, is there any difference between using arrow
functions and bind manually when using es6 classes? Using arrow
functions the methods are not on the class prototype, it will be on
the class instance only. Using bind will attach the methods to class
prototype. It sounds like bind manually will have better performance,
does that mean we should consider using bind instead of arrow
functions for class methods?
Any suggestions or comments are really appreciated!
So in terms of performance, would you recommend using
class MyComponent extends React.Component { constructor(props) {
super(props) }
methodA = () => { ... } }
or
class MyComponent extends React.Component { constructor(props) {
super(props)
this.methodA = this.methodA.bind(this) }
methodA() { ... } }
Answer:
These two ways of writing it are equivalent. (The second one is
compiled to the first one.)
Using bind will attach the methods to class prototype.
In your example, you still attach the function to the instance:
this.methodA = this.methodA.bind(this)
So they’re essentially the same.
At Facebook, we use the second way (“class properties”) but be aware
this is still experimental, and not part of ES6. If you only want to
stick with stable syntax, then you could bind them manually.
First approach is correct performance wise, because on every render this onClick prop will be pointing to the same object, which is not the case in the second example.
If you look at the below example, you will see when I increment the counter, the MyPureCompOne doesn't render, but MyPureCompTwo does. Because each time time the <App> component renders, MyPureCompTwo props handleClick being assigned with a new function object, and that is why being a pure component shallow comparisons of props are false and it renders. This rendering was not needed. But that is not the case with MyPureCompOne, as each time time App renders, the handleClick props still pointing to the same function object (this.handleClickOne) which was created when the App first time mounted.
class MyPureCompOne extends React.PureComponent {
render() {
console.log("rendring component one");
return <button onClick={this.props.handleClick}>First Button</button>
}
}
class MyPureCompTwo extends React.PureComponent {
render() {
console.log("rendring component two");
return <button onClick={this.props.handleClick}>Second Button</button>;
}
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
this.handleCountChange = this.handleCountChange.bind(this);
this.handleClickOne = this.handleClickOne.bind(this);
}
handleCountChange() {
this.setState(prevState => ({
count: prevState.count + 1
}));
}
handleClickOne(e) {
console.log("Clicked..");
}
handleClickTwo() {
console.log("Clicked..");
}
render() {
const { count } = this.state;
return (
<div>
<button onClick={this.handleCountChange}>Change Counter</button>
<MyPureCompOne handleClick={this.handleClickOne} />;
<MyPureCompTwo handleClick={this.handleClickTwo.bind(this)} />
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script crossorigin src="https://unpkg.com/react#16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.production.min.js"></script>
<div id='root'></div>
I took this from the eslint-plugin-react documentation:
A bind call or arrow function in a JSX prop will create a brand new function on every single render. This is bad for performance, as it will result in the garbage collector being invoked way more than is necessary. It may also cause unnecessary re-renders if a brand new function is passed as a prop to a component that uses reference equality check on the prop to determine if it should update.
As a side note from me, using this in your JSX can be confusing as well. I encourage you to take a look at this doc: https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md
You should avoid arrow functions and binds in render. It breaks performance
optimizations like shouldComponentUpdate and PureComponent.
For an excellent read and demo you might want to refer
this.

Why does it give an error 'searchInput' of undefined

I want to search for people. An array of data is stored in the redux store. I'm trying to perform a search, but an error occurs.
Cannot read property 'searchInput' of undefined
What could be the problem?
searchHandler(){
console.log('findUser', this.searchInput.value);
this.props.onFindPeople(this.searchInput.value)
}
I add an example code
You lost the context of this to the event handler.
You can either use an arrow function (that uses a lexical context for this):
searchHandler = () => {
console.log("findUser", this.searchInput.value);
this.props.onFindPeople(this.searchInput.value);
}
Or bind it to the class like this:
constructor(props){
super(props);
this.searchHandler = this.searchHandler.bind(this);
}
We do it in the constructor because it will run only once.
You are not binding the function. You need to bind it in constructor like below. Binding is required in order to access this and access state, props and modifying the state.
Please note you need to bind it only in constructor not anywhere else in the component
constructor(props){
super(props);
this.searchHandler = this.searchHandler.bind(this);
}
searchHandler(){
console.log('findUser', this.searchInput.value);
this.props.onFindPeople(this.searchInput.value);
}
Or you can also use arrow function as Sagiv mentioned in his answer.

constructor/super/bind in React usage's what do they specify does?

I looked up what does constructor, super and bind does in General JS.
Example code.
import React from 'react';
class Example extends React.Component {
constructor(props){
super(props);
this.state = { mood: confused }
this.doNothing = this.doNothing.bind(this);
}
doNothing(){} //I really do nothing
render(){
<button onClick={this.doNothing}>I do nothing xD</button>
}
}
Here is what I understand for now
State is an object, in order to create an object within a class I need to use constructor
subclass's constructor will override the parent's constructor, I don't know what is in React.Component but I am sure it is important. I think it is also said in React Document:
Class components should always call the base constructor with props.
super will help me do inherit, and super is the replacement of the parent's constructor. If I need to use this in constructor I need to write super and to go further, I need to pass a parament do super(props) to use this.props
bindwill create a new function that is bounded well with the object, making sure when the function is called, it will be direct to the right object because for some reason if I don't bind it, my button will be like <button onClick={undefined.doNothing}>, because of some class rule :/ (the optional paraments can also help me set pre arguments which are interesting but that isn't what bothers me)
Here is what I don't understand
The meaning of arguments I passed, I have seen some example but they didn't really pass any argument. (The props constructor(props) super(props))
The whole bind code looks odd to me, this.doNothing is changed into what? this.this.doNothing? How does it really works, why my button knows where to find it?
I know this is kinda basic but I did try my best looking things up, I will appreciate if anyone can help me out.
State is an object, in order to create an object within a class I need
to use constructor
You can create whatever object inside a class. Just that state is a special one in React: it need to be defined in constructor to be used in React component life-cycle.
subclass's constructor will override the parent's constructor, I don't
know what is in React.Component but I am sure it is important.
constructor, to my understanding, has three jobs: (1) allows access to this.props by super(props), (2) initialises state and (3) binds functions.
Your later part is on the point.
bindwill create a new function that is bounded well with the object,
making sure when the function is called, it will be direct to the
right object because for some reason if I don't bind it, my button
will be like 'button onClick={undefined.doNothing}>, because of some
class rule
this in React component refers to the component itself. Functions provided by React.Component, e.g. render always have this binding to the component, while your own defined functions don't. So <button onClick={this.doNothing}> in render() will not pose any issue, but doNothing() needs to be bound in constructor to get access to this.
The meaning of arguments I passed, I have seen some example but they
didn't really pass any argument. (The props constructor(props)
super(props))
Look up to point 1. If you use super() instead of super(props), this.props will be undefined inside constructor. It is still accessible in other functions.
Here is the original answer to this.
The whole bind code looks odd to me, this.doNothing is changed into
what? this.this.doNothing? How does it really works, why my button
knows where to find it?
Look up to point 4. this.doNothing().bind(this) allows you to access this inside function doNothing(), including reading state, props and calling other functions of the component. Without binding, this will be undefined inside doNothing().
When you define a variable using the this keyword, it belongs to the scope of the React class and hence can you used throughout the scope of the React class.
The meaning of arguments I passed, I have seen some example but they
didn't really pass any argument.
As far as bind is concerned, .bind takes the context as an argument and returns a function, which when executed will refer to the context of the React class. The rest of the arguments that are passed to bind are made available to the function when it is called.
For example when you write
constructor(props){
super(props);
this.doNothing = this.doNothing.bind(this);
}
The function that is returned by bind is assigned to a variable doNothing which is defined in the class scope. If you change it to
constructor(props){
super(props);
this.someNewFunction = this.doNothing.bind(this);
}
you will use it like
render(){
<button onClick={this.someNewFunction}>I do nothing xD</button>
}
You already set props yourself without knowing:
<button onClick={this.doNothing}>
Here onClick will be set to this.doNothing inside of the props passed to the button constructor. To pass props to your Example class one can do:
<Example color="blue" />
Now in the render method for example you can access it as:
<button style = {{ color: this.props.color }} > Some button </button>
Through that your components can be reused at different places, as the parent can change their props to define their behaviour.

Why exactly is bind(this) necessary in React constructors? [duplicate]

Something that is puzzling me is why when I define a react component class, values contained in the this object are undefined in methods defined (this is available in lifecycle methods) within the class unless I use .bind(this) or define the method using an arrow function for example in the following code this.state will be undefined in the renderElements function because I did not define it with an arrow function and did not use .bind(this)
class MyComponent extends React.Component {
constructor() {
super();
this.state = { elements: 5 }
}
renderElements() {
const output = [];
// In the following this.state.elements will be undefined
// because I have not used .bind(this) on this method in the constructor
// example: this.renderElements = this.renderElements.bind(this)
for(let i = 0; i < this.state.elements; i ++){
output.push(<div key={i} />);
}
return output;
}
// .this is defined inside of the lifecycle methods and
// therefore do not need call .bind(this) on the render method.
render() {
return (
<div onClick={this.renderElements}></div>
);
}
}
Then in the following example I do not need to use .bind(this) or an arrow function, this is available as expected in speak function
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(this.name + ' makes a noise.');
}
}
class Dog extends Animal {
speak() {
console.log(this.name + ' barks.');
}
}
var d = new Dog('Mitzie');
d.speak();
http://jsbin.com/cadoduxuye/edit?js,console
To clarify, my question is two part. One) why in the second code example do I not need to call .bind(this) to the speak function, but I do in the React component for the renderElements function and Two) why do the lifecycle methods (render, componentDidMount, etc) already have access to the class' this object, but renderElements does not.
In the React docs it says the following
[React Component Class] Methods follow the same semantics as regular ES6 classes, meaning that they don't automatically bind this to the instance.
But clearly they do, as the second code example I've posted shows.
Update
Both links in the first two comments show a working example of React classes NOT using .bind(this) on class methods and it works fine. But still in the docs is explicitly says you need to bind your methods, or use an arrow function. In a project using gulp and babel I can reproduce. Could it mean browsers have updated things?
Update 2
My initial code example had this.renderElements() called directly in the render function. That would work as expected without binding the function, or defining it with an arrow function. The issue occurs when I put the function as an onClick handler.
Update 3
The issue occurs when I put the function as an onClick handler.
In fact it is not an issue at all. The context of this changes when passed to the onClick handler, so that's just how JS works.
The value of this primarily depends on how the function is called. Given d.speak();, this will refer to d because the function is called as an "object method".
But in <div>{this.renderElements}</div> you are not calling the function. You are passing the function to React which will call it somehow. When it is called, React doesn't know which object the function "belonged" to so it cannot set the right value for this. Binding solves that
I actually think what you really want is
<div>{this.renderElements()}</div>
// call function ^^
i.e call the function as an object method. Then you don't have to bind it.
Have a look at MDN to learn more about this.
Event handlers in the component will not be bound automatically to the component instance like other methods ( life cycle methods...).
class MyComponent extends React.Component {
render(){
return (
<div onClick={this.renderElements}>
{this.renderElements()} <-- `this` is still in side the MyComponent context
</div>
)
}
}
//under the hood
var instance = new MyComponent();
var element = instance.render();
//click on div
element.onClick() <-- `this` inside renderElements refers to the window object now
Check this example to understand this more :
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(this.name + ' makes a noise.');
}
}
class Dog extends Animal {
run(){
console.log(this.name + ' runs');
}
speak() {
console.log(this.name + ' barks.');
this.run(); <-- `this` is still in the Dog context
return {onRun : this.run};
}
}
var d = new Dog('Mitzie');
var myDog = d.speak();
myDog.onRun() <-- `this` is now in the global context which is the `window` object
You can check this article for more information.
Functions in ES6 Classes - the case is explained very well by #Felix Kling. Every time you call a function on an object, this points to the object.
Lifecycle methods in React.Component - whenever React instantiates your component like myComponent = new MyComponent() it knows which object to call the lifecycle methods on, namely myComponent. So a simple call myComponent.componentDidUpdate() makes this available in the componentDidUpdate lifecycle method. Same for the other lifecycle methods.
Handlers & Bound in React.Component - this.state is undefined, because this is actually window - log it and see. The reason is that React invokes handlers on the global context, unless you have the handler bound to another context which overrides window (see #Phi Nguyen's answer also).
I think they have done that to allow you more flexibility, because in complex applications your handler may come from another component passed through props and then you would like to have the possibility to say: "Hey, React - this is not my component, but it's parent."
React's documentation is a bid misleading when it says
Methods follow the same semantics as regular ES6 classes, meaning that
they don't automatically bind this to the instance.
What they mean is that
var dog = new Dog('Mitzie');
speak = d.speak;
dog.speak() // this will be dog, because the function is called on dog
speak() // this will be window, and not dog, because the function is not bound
1.
Arrow Functions:
An arrow function expression has a shorter syntax compared to function expressions and lexically binds the this value (does not bind its own this, arguments, super, or new.target). Arrow functions are always anonymous. These function expressions are best suited for non-method functions and they can not be used as constructors.
Function.prototype.bind():
The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.
2.Component Specs and Lifecycle
To be absolutely clear: Most lifecycle methods are not bound, but called on an instance using the dot notation (true for componentWillMount, componentWillUnmount, componentWillReceiveProps and so on...), except componentDidMount which is bound to the instance since it gets enqueued into the transaction.
Just always put the autoBind(this); code in your constructor and never worry about method pointers.
npm install --save auto-bind-inheritance
const autoBind = require('auto-bind-inheritance');
class Animal {
constructor(name) {
autoBind(this);
this.name = name;
}
printName() { console.log(this.name); }
...
}
let m = new Animal('dog');
let mpntr = m.printName;
m.printName() //> 'dog'
mpntr() //> 'dog', because auto-bind, binds 'this' to the method.

Class properties for react lifecycle methods

Can I write React lifecycle methods as class properties?
I've been using class properties for a while as I like the fact that I no longer have to manually bind my methods, but I'd like to keep some consistency across my components and I'm wondering if there is any drawback on writing the React lifecycle methods as class properties
import React, { Component } from 'react';
class MyComponent extends Component {
render = () => {
return (
<div>Foo Bar</div>
);
}
}
export default MyComponent;
For example, is the context of this class property affected compared to the context in an equivalent method. Given that the render method in the above code is written as an arrow function, this concern seems relevant.
In a way, the true answer depends on your build pipeline and what the resulting Javascript output looks like. There are two primary possibilities:
Input Code
Let's start by saying you are writing the following before going through any sort of pipeline transformations (babel, typescript, etc):
class Test {
test = () => { console.log('test'); };
}
Output as class member variable.
In one possible world, your pipeline will also be outputting the test function as a member variable for the output class. In this case the output might look something like:
function Test() {
this.test = function() { console.log('test'); };
}
This means that whenever you write new Test() the test function is going to be recreated every single time.
Output as class prototype function
In the other major possibility, your pipeline could be recognizing this as a function property and escape it from the class instance to the prototype. In this case the output might look something like:
function Test() {
}
Test.prototype = {
test: function() { console.log('test'); }
}
This means that no matter how many times you call new Test() there will still be only one creation of the test function around in memory.
Desired behavior
Hopefully it's clear that you want your end result to have the function end up on the prototype object rather than being recreated on each class instance.
However, while you would want the function to not end up as a property, that doesn't necessarily mean you couldn't write it that way in your own code. As long as your build chain is making the correct transformations, you can write it any way you prefer.
Although, looking at the default babel settings (which your babeljs tag leads me to believe you are using) it does not make this transformation for you. You can see this in action here. On the left I've created one class with the function as a property and one class with the function as a class method. On the right hand side, where babel shows it's output, you can see that the class with the function as a property still has it being an instance-level property, meaning it will be recreated each time that class's constructor is called.
I did find this babel plugin, which seems like it might add this transformation in, but I've not used it for myself so I'm not positive.
In my experience, the most reason for writing a method as a class property is when the method will be passed as a callback, and you need it to always be bound to the instance. React lifecycle methods will always be called as a method, so there's no reason to bind them (and you incur a tiny memory penalty when you do). Where this makes a difference is when you're passing a function to a component as a callback (e.g. onClick or onChange).
Take this example:
class BrokenFoo extends React.Component {
handleClick() {
alert(this.props.message);
}
render() {
return (
<button onClick={this.handleClick}>
Click me
</button>
)
}
}
The function represented by this.handleClick is not automatically bound to the component instance, so when the method tries to read the value of this.props it will throw a TypeError because this is not defined. Read this article if you're not familiar with this; the problem described in section 4.2 "Pitfall: extracting methods improperly" is essentially what's happening when you pass around a method without making sure it's bound correctly.
Here's the class, rewritten with the handler as a class property:
class HappyFoo extends React.Component {
handleClick = () => {
alert(this.props.message);
}
render() {
return (
<button onClick={this.handleClick}>
Click me
</button>
)
}
}
Effectively, you can think of the handleClick definition in the second example as placing this code into the component's constructor (which is just about exactly the way Babel does it):
this.handleClick = () => {
alert(this.props.message);
}
This achieves the same thing as calling bind on the function (as described in the linked article) but does it a little differently. Because this function is defined in the constructor, the value of this in this.props.message is bound to the containing instance. What this means is that the function is now independent of the calling context; you can pass it around and it won't break.
The rule of thumb that I follow: by default, write methods as methods. This attaches the method to the prototype and will usually behave the way you'd expect. However, if the method is ever written without parentheses (i.e. you're passing the value and not calling it), then you likely want to make it a class property.

Categories

Resources