How "this" got binded in the React component method - reactjs

I have abstracted my React code here. I have not binded "this" to method A(). That is , in the constructor I didnot do
this.A = this.A.bind(this);
nor used any arrow syntax for binding.
So the compiler cannot know what's the value of this inside A().
Since I have used this.map inside A(), the compiler should have thrown error for this usage. When inspecting the code in Chrome Dev Tools, I found the compiler seems to correctly assign the value of this automatically by var _this2 = this. I couldnt understand the behaviour. Can somebody explain this pls. (I am new to React. Kindly bear if this question sounds silly)
class Test extends React.Component{
constructor(props){
super(props);
this.map = [];
this.state = { a: 1};
}
A(){
// some complex logic
this.map = Complexlogic() ;
}
componentWillMount(){
this.A();
}
}

React has created class constructs partially for this purpose. By design, anything created within a class construct is bound to the object context, as it would in any other language's class.
Why you often see functions being 'bound' inside class constructs is for when they have to be passed outside the class context, but you wish to maintain the context of the object for that function. Such as when you pass a function to a component in the render call.
As for why you see "_this2" - its just a way that react manages several different "this" contexts being available at a given time.

Related

Calling component in react

I am new in react and i come to this new syntax please help me to understand it better.
class Car extends React.Component {
constructor() {
super();
this.state = {color: "red"};
}
render() {
return <h2>I am a {this.state.color} Car!</h2>;
}
}
root.render(<Car color="red"/>);
I have created a class component and as in object oriented programing we should create the instance of class to use it but here we are not initiating a class instance we just write the name of class in jsx language.
can anyone help me here what's happening behind the scene.
Actually react take cares of it on its own. We dont need to create instance while using recactjs.
please read the explanation here in offcial doc of reactjs.
(There mentioned below sentence.)
"Function components don’t have instances at all. Class components
have instances, but you never need to create a component instance
directly—React takes care of this."
https://reactjs.org/blog/2015/12/18/react-components-elements-and-instances.html
React is a library and does it so you don't have to worry about it.
The syntax you just saw is JSX. It is just syntactic sugar for React.CreateElement. And when you go to the React source code you can see that a constructor is actually called.
return ReactElement(
type,
key,
ref,
self,
source,
ReactCurrentOwner.current,
props,
);
Here ReactElement is a factory method. It creates an object and returns that. But you never have to worry about it.
It is like worrying about addEventListener. How do you know it actually works? :D
PS: There are no real classes in JS. ES6 classes are just an abstraction and are actually created using functions only.

When do I need to use bind() in reactJS and react native

so when I create a class I it ususally look something like this
export default class SettingsIndex extends Component {
constructor(props) {
super(props);
this.state = {
testValue: 1,
};
}
myfunction(){
this.setstate({value: 2)
}
render(){
return(
........
Question 1:
To be honest, I am not sure when I really need to have the constructor, in my understanding is that I need to declare the constructor every time a class is receiving props from a parent component, is that assumption correction?
Question 2:
see myfunction() in some classes it works without issue, however in some classes I have I get an error saying ```this.myfunction' is undefined and I then I need to bind(this) in the constructor like this
this.myfunction= this.myfunction.bind(this);
I am not sure why in some class this is accessible and not other, any idea?
You need to use the constructor only when you need to have some initialisation logic which needs to run before the first render such as initialising refs, state or binding functions. You do not require constructor just beecause your component is receiving props, React itself can do that prop forwarding for you
For your case you can define state as a class initialiser too with proper babel setup and get rid of the constructor
export default class SettingsIndex extends Component {
state = {
testValue: 1,
};
myfunction(){
this.setstate({value: 2)
}
}
Now as far as the question about binding is concerned, you first need to understand how does a function receive its context or this variable.
The this argument to a function call is received as the reference of the object on which the function is called unless the function is defined as an arrow function in which case it inherits the this variable from its surrounding scope or this is explicitly overwritten by use of call, apply or bind methods
For Example, in the lifeecycle meethods of React, the this variable already points to the class instance and calling a function using this.myFunction() will causee the myFunction to receive the context of the class as the object on which it is called is this.
On the other hand when you assign the function to an event handler, you are assigning a reference to it and when the event occurs the function is ccalled on the window reference causing the this to be undeefined and thus nneeding you to use arrow function or explicit bind to supply proper context.
Check this SO post for more details on this keyword

Use state, static defaultProps or a property to hold static data

Currently, I have in my state a property holding the following value
state = {
listOfCategories = ['Bank', 'Home', 'News']
}
That piece of state is never going to change (I will use it in that component and a direct children). So I'm thinking if I should remove it from the state, which to my understanding is meant for mutable data, and put it as a property of the Class or defaultProps of that Class.
Which approach should I follow?
That piece of state is never going to change
You can even extract listOfCategories = ['Bank', 'Home', 'News'] completely outside of React tree (or put in a different file, to use it elsewhere as well).
the state, which to my understanding is meant for mutable data,
The state should be immutable because React does "shallow check" (checks if reference has been changed, not the deep comparison, which checks for changed value for nested properties as well).
a property of the Class or defaultProps of that Class.
If listCategories belongs to the current component, then it'd make sense to declare it as a property because listCategories is the component's own property, not changed by parent's props (as you said it never changes).
Well i think every solution you expose are good.
But let's come back to basic :)
You create a class with react propertys but it still a simple class.
So why not just declare this array as member of this class like this :
class test extends React.Component {
constructor(props) {
super(props);
this.state = {
test: props.FakeData
}
this.listOfCategories = ['Bank', 'Home', 'News']
}
}
simple, easy and in my opinion the best way to do it.

Binding in React: What does `this` refer to if I don't bind?

I had some problems to understand the whole this issue in React (or JS in general) and found this very helpful article:
https://medium.freecodecamp.org/react-binding-patterns-5-approaches-for-handling-this-92c651b5af56
However, there is one basic thing that I'm still not sure about.
Let's take the Approach 2 as an example:
// Approach 2: Bind in Render
class HelloWorld extends React.Component {
constructor(props) {
super(props);
this.state = { message: 'Hi' };
}
logMessage() {
// This works because of the bind in render below.
console.log(this.state.message);
}
render() {
return (
<input type="button" value="Log" onClick={this.logMessage.bind(this)} />
);
}
}
Now, let's look at the wrong version of this code where we just do not do the binding that is required in order to refer to the right this (the HelloWorld component):
// Wrong "naive" version of the code
class HelloWorld extends React.Component {
constructor(props) {
super(props);
this.state = { message: 'Hi' };
}
logMessage() {
// This works because of the bind in render below.
console.log(this.state.message);
}
render() {
return (
<input type="button" value="Log" onClick={this.logMessage} />
);
}
}
My question is very simple: In that wrong version, it is my understanding that the this in console.log(this.state.message) within the logMessage function does not refer to the HelloWorld class object anymore. What does it refer to instead? Thank you!
EDIT: Turns out my understanding is wrong. This is not the this that does not work anymore. It's "the other" this at onClick={this.logMessage}! The reason will be given in the answers below - just wanted to correct this right here in the question.
Whenever you call a function using - (), the function context - this is set automatically based on whatever goes before ().
For example,
let A = {
foo() {
console.log(this === A);
}
};
when you call foo like this -
A.foo() // prints true
the context function foo receives depends on A.foo, here it is A. But when you call the SAME function using a different member - for example -
let B = {
foo: A.foo
};
B.foo(); // prints false
Even though you're still calling the exact same function, the function/method foo receives a different context (here B) -
And sometimes, you can force the context of a function using one of these three things -
1. .bind
Docs: MDN
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. .call, .apply
Both of them call the function with a given this value.
Docs: MDN Function.prototype.call
Docs: MDN Function.prototype.apply
3. Arrow function
Docs: MDN Arrow functions
class
JavaScript class methods have the same concepts -
class A {
foo() {
console.log(this instanceof A);
}
}
let a = new A();
a.foo(); // prints true
and when you run the experiment of assigning this function to a different method of a different object,
let b = {
foo: a.foo
};
b.foo(); // prints false
Whenever you pass a function somewhere else, you're not passing the context along with it, but you're expecting some context inside your function by using this and
The source of the issue
In your example,
<input type="button" value="Log" onClick={this.logMessage} />
specifically,
onClick={this.logMessage}
which is analogous to the above example -
let b = {
foo: a.foo
};
So, now, whoever calls your function using b.foo (here React) needs to know the context. So you have to set the context for the function before you pass it to onClick
What does it refer to instead if you don't bind?
In strict mode, the following happens -
Thus for a strict mode function, the specified this is not boxed into an object, and if unspecified, this will be undefined
Source: MDN under the section "Securing JavaScript"
And in all of the above examples with b.foo, if you assign it to a variable instead of object property,
let c = a.foo;
c(); // this will be undefined in foo
So, in your logMessage method, the value of this will be undefined.
this always refers to your class' attributes and behaviors but you have to bind this to the functions in which you want to use those attributes and behaviors. If you do not bind class level this with a function so "this" in that function refers to the attributes within the context of that function only.
You can also bind this in component cycle's callbacks like componentWillMount, constructor or anywhere where this has the reference to the class.
Forexampe:
componentWillMount(){
this.anyCallBack = this.anyCallBack.bind(this);
}
anycallBack(){
//now this will refer to the class
console.log(this);
}
The default value of 'this' depends on which event you are binding to. With JavaScript, in general, DOM events, such as onClick or onChange have 'this' as a pointer to the DOM element that triggered the event. For instance, if you were to create a button and attach a click listener, and in that listener, use console.log(this) you will see the button is the value of this.
Note: React has 'this' set as undefined by default.
Event handlers for setTimeout and setInterval, will set 'this' as a pointer to the window object.
There is an inherit danger to using bind. Each time you bind to a method, JavaScript creates a new method. The new method is an anonymous method unless you set it's value to a property or variable:
let myBoundMethod = myMethod.bind(this);
If you need to detach an event from a DOM element, unless you have a reference to the bound method, you will not be able to remove the event listener from the event. This can be a source of memory leaks in your application. Always use your debugging tools to monitor memory usage. It is normal for it to go up and down, but it should have a relatively stable baseline.
DOM elements removed from the DOM will often garbage collect along with their event listeners, but if there is still a reference in memory to the element, it will not be garbage collected.

How can I tell when this.setState exists in ES6?

I have been struggling with trying to migrate my React code from ES5 to ES6. As I have found out by now, this is no longer automatically bound which causes all sorts of hell.
I am trying to figure out by trial and error what objects are being passed around. So far I can find everything and adjust accordingly. However when it comes to this.setState I am having problems because it is not visible in console.log!!!! See screenshot in ES5:
and here is the same kind of code in ES6:
Please teach me how to fish i.e. help me figure out how to understand when an object has this.setState or not?
things i have tried
from googling around i understand you might be able to default bind everything by changing the base component. unfortunately this did not work when it came to this.setState. It looks identical to the ES5 version of this in console so I concluded that setState is still not being bound somehow
To oversimplify how this works in JS:
If you call a function as an object method (e.g., instance.foo()) then this refers to that object instance.
If you call a function by itself (e.g., foo()), then this is either undefined or the global object, depending on whether strict mode is in effect.
If you take a reference to an object method then call it, that means you're calling it by itself, even though it was originally an object method. (E.g., var bar = instance.foo; bar();.
Again, this is an oversimplification; MDN has details.
As this applies to React, and as explained in the React documentation on "Handling Events":
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.
In your code, you render your RawInput as
<RawInput value={this.state.value} updateValue={this.updateValue}/>
You're passing a reference updateValue function in as a simple function, so this will not be bound within updateValue.
Basically, any time you pass a function as a React prop, unless you've bound it yourself, it's likely an error. The symptom is typically that this is undefined. In your code, it's a little more complicated:
this.props.updateValue(modifiedValue);
The RawInput's updateValue property is the unbound function App.updateValue, but because you're invoking it as this.props.updateValue, it's being called as if it were a method of this.props - so this refers to the RawInput's props. That's why your console.log is showing an object with only two properties (start and updateValue): it isn't that setState isn't bound or went away, it's that updateValue wasn't bound, so this isn't what you expect within updateValue.
To fix the issue, as the React docs explain:
Use a fat arrow function: updateValue={(value) => this.updateValue(value)}
Use the experimental property initializer syntax: Replace updateValue(modifiedValue) {...} with updateValue = (modifiedValue) => {...}.
Not mentioned in the React docs, but an approach I often use: Bind updateValue yourself. For example:
constructor(props) {
super(props);
this.updateValue = this.updateValue.bind(this);
}
you can replace console.log with this:
console.shallowCloneLog = function(){
var typeString = Function.prototype.call.bind(Object.prototype.toString)
console.log.apply(console, Array.prototype.map.call(arguments, function(x){
switch (typeString(x).slice(8, -1)) {
case 'Number': case 'String': case 'Undefined': case 'Null': case 'Boolean': return x;
case 'Array': return x.slice();
default:
var out = Object.create(Object.getPrototypeOf(x));
out.constructor = x.constructor;
for (var key in x) {
out[key] = x[key];
}
Object.defineProperty(out, 'constructor', {value: x.constructor});
return out;
}
}));
}
any way, regarding your question, you can add a method like this:
updateValue = () => {...}
in m POV - es6 is cool and great. React components by es6' classes are useless. stick with createClass and you'll be fine (and have mixins if you want!)
Try Object.prototype.hasOwnProperty(). For example:
var X = function() {};
X.prototype.setSomething = 'a';
var x = new X();
x.setSomething; // log 'a' here
x.hasOwnPrperty('setSomething') // log false here
In your case, just console.log(this.hasOwnProperty('setState')).
You have to bind your updateValue function with the component in order to have the correct context (this).
In your case, your parent class BaseComponent allows you to use the herited method _bind like that :
class App extends BaseComponent {
constructor(props){
super(props);
this.state={value:'start'};
this._bind('updateValue');
...

Resources