React - class method syntax [duplicate] - reactjs

It seems to me that, in ES6, the following two functions are very nearly identical:
function () {
return this;
}.bind(this);
() => {
return this;
};
The end result seems the same: arrow functions produce a JavaScript function object with their this context bound to the same value as the this where they are created.
Obviously, in the general sense, Function.prototype.bind is more flexible than arrow functions: it can bind to values other than the local this, and it can bind any function's this at any point in time, potentially long after it is initially created. However, I'm not asking how bind itself is different from arrow functions, I'm asking how arrow functions differ from immediately calling bind with this.
Are there any differences between the two constructs in ES6?

There are no (significant) differences.
Well, okay, that's a little premature. There are three tiny differences unique to arrow functions.
Arrow functions cannot be used with new.
This means, of course, that they do not have a prototype property and cannot be used to create an object with the classically-inspired syntax.
new (() => {}) // TypeError: () => {} is not a constructor
This is probably for the best, though—the way new works would not make much sense with bound functions.
Arrow functions do not have access to the special arguments object that ordinary JavaScript functions have access to.
(() => arguments)(1, 2, 3) // ReferenceError: arguments is not defined
This one is probably a little bit more of a gotcha. Presumably this is to remove one of JavaScript's other oddities. The arguments object is its own special beast, and it has strange behavior, so it's not surprising that it was tossed.
Instead, ES6 has splats that can accomplish the same thing without any magic hidden variables:
((...args) => args)(1, 2, 3) // [1, 2, 3]
Arrow functions do not have their own new.target property, they use the new.target of their enclosing function, if it exists.
This is consistent with the other changes to remove "magically" introduced values for arrow functions. This particular change is especially obvious, considering arrow functions can't be used with new anyway, as mentioned above.
Otherwise, arrows are just like bound functions, semantically. It's possible for arrows to be more performant, since they don't have to carry around the extra baggage and since they don't need to be converted from ordinary functions first, but they're behaviorally exactly the same.

There are a few differences:
Arrow functions cannot be constructed. While both arrow functions and bound functions both don't have a .prototype property, the former do throw an exception when called with new while the latter just ignore the bound value and call their target function as a constructor (with the partially applied bound arguments, though) on the new instance.
function F() {}
var f = () => {},
boundF = F.bind({});
console.log(new boundF(), new boundF instanceof F) // {}, true
console.log(new f) // TypeError
Arrow functions do have lexical arguments, new.target and super as well (not only lexical this). A call to an arrow function does not initialise any of those, they are just inherited from the function the arrow function was defined in. In a bound function, they just refer to the respective values of the target function.
Arrow functions don't actually bind a this value. Rather, they don't have one, and when you use this it is looked up like a variable name in the lexical scope. This does allow you to lazily define an arrow function while this is not yet available:
class X extends Object {
constructor() {
var f = () => this, // works
boundF = function(){ return this; }.bind(this);
// ^^^^ ReferenceError
super(); // initialises `this`
console.log(f(), f() == this); // {}, true
}
}
new X;
Arrow functions cannot be generator functions (though they can return generators). You can use .bind() on a generator function, yet there is no way to express this using an arrow function.

Here is one more subtle difference:
Arrow functions can return a value without using the 'return' keyword, by omitting the {} braces following the => immediately.
var f=x=>x; console.log(f(3)); // 3
var g=x=>{x}; console.log(g(3)); // undefined
var h=function(x){x}; console.log(h(3)); // undefined
var i=x=>{a:1}; console.log(i(3)); // undefined
var j=x=>({a:1}); console.log(j(3)); // {a:1}

Related

React unsubscribe from RxJS subscription in useEffect

A quick question regarding RxJS in useEffect hooks
I've noticed the React community uses this unsubscribe pattern with RxJS:
useEffect(()=>{
const sub = interval(10).subscribe()
return ()=>sub.unsubscribe()
})
I'm curious if this is due to convention/code clarity, or if I'm overlooking something. I would imagine the following would be simpler:
useEffect(()=> interval(10).subscribe().unsubscribe)
However, I could be overlooking something.
Edit: View selected answer. "This" is bound on method call, rather than on subscription instantiation. As a result, unsubscribe fails due to the "this" object not referring to the interval subscription, but rather the useEffect callback environment. Thanks to both contributors. Here is an example of the useEffect hook failing: codesandbox.io/s/morning-bush-7b3m6h?file=/src/App.js
This here:
useEffect(()=>{
const sub = interval(10).subscribe();
return () => sub.unsubscribe();
});
could be re-written as:
useEffect(()=>{
const sub = interval(10).subscribe();
function unsub(){
sub.unsubscribe();
}
return unsub;
});
The key thing to notice is that you're returning a function back to React. unsub isn't called right away, it's called later when the component unmounts.
In fact, you can return arbitrary code to be run later:
useEffect(() => {
/******
* Code that gets called when
* effect is run
******/
return () => { // <- start of cleanup function
/******
* Code that gets called to
* clean up the effect later
******/
} // <- end of cleanup function
});
The problem
I'll rewrite your solution to make talking about the problem clearer. This is semantically equivalent, I've just introduced an intermediate variable.
useEffect(() =>
const sub = interval(10).subscribe();
return sub.unsubscribe;
);
The the question most clearly boils down to: What are the differences between these values? Under which circumstances (if any) will one fail while the other does not.
sub.unsubscribe
() => sub.unsubscribe()
If unsubscribe is a function (isn't bound to an instance of a class/object because it doesn't contain the this keyword), then the two are semantically equivalent.
The issue is that unsubscribe is not actually a function. It's a method on an subscription object. Because of this, the first value above is an unbound method where this is undefined. The moment the method attempts to use its context (this), JavaScript will throw an error.
To make sure that unsubscribe gets called as a method you could do this:
useEffect(() => {
const sub = interval(10).subscribe();
return sub.unsubscribe.bind(sub);
});
You have one less level of indirection this way, though it looks roughly the same.
Furthermore, I would recommend against using bind in most cases. Methods, functions, anonymous lambda functions, and attributes containing any of these three as values all behave differently on various edge cases.
As far as I know, () => a.b() may be needlessly wrapping a function, but will not fail. Plus JIT will optimize this fairly well 99.9% of cases.
Where a.b.bind(a) will fail on a previously bound method, but be optimized 100% of the time. I wouldn't use bind unless it's necessary (and it rarely is)
Update:
Just a quick aside: I use function here to denote a callable block of code which doesn't rely on a context (Doesn't have an object that it references using the this keyword) and a method to denote a callable block of code that DOES rely on some context.
If you prefer other terminology, that's fine. Swap out the words as you read them, I won't take offense, promise :)
Beware of this
The short answer is that the unsubscribe function uses the this keyword and was designed to be called as a property of the subscription object (e.g., as subscription.unsubscribe()) rather than "on its own" (e.g., as just unsubscribe()`).
What is this?
In JavaScript (in addition to the arguments passed to it and the closed-over values in scope) a function may use the this keyword to access a special contextual value. Originally, this was meant to be equal to the "receiver", or the object that the function was being called from. For example, if you set a.f = f and b.f = f with any function f, you can call a.f() and this will be equal to a or call b.f() and this will be equal to b. If you call f() by itself, this will be undefined.
How does that matter?
In this case, interval(10).subscribe() returns a Subscription object with an unsubscribe function that expects this to be that same subscription object. Particularly, this line of the current source code for unsubscribe checks this.closed to avoid re-closing subscriptions that have already been closed.
So, while you're permitted to pull interval(10).subscribe().unsubscribe away and call it without a receiver, you will get an error like "Cannot read properties of undefined (reading 'closed')".
What can I do about it?
Unfortunately, it's not always clear when this is being used in a function that you didn't write. It's best to avoid isolating a function that came from an object (e.g., const f = obj.func;) unless you're sure it's this-free. But if a function is already "on its own", you don't usually have to worry about this.
However, there are the following workarounds:
Wrap it in a new function that always calls it with the expected receiver. This is what your example does: () => sub.unsubscribe().
Create a "bound" copy of the function. Functions are objects too, and available to each function is the bind function that can be used to sort of hard-code the value of this. If you write const unsub = sub.unsubscribe.bind(this);, calling unsub will always call the unsubscribe function with sub as the value of this. This practically very similar to option 1 in that it creates a new function, but this is more streamlined to its purpose.
Use an "arrow" function. This isn't something consumers can do, but the rxjs authors could have written it this way: unsubscribe = () => { ... }. Then you could pull the function out and use it by itself with no errors. This is because "arrow" functions — functions created with the () => ... syntax — have special behavior: they always preserve this from wherever they were created. So when constructing a new Subscription(), it gets a dedicated unsubscribe function whose this value will always equal the constructed subscription object. But since the unsubscribe function is currently declared without the arrow syntax, it uses the typical this-equals-receiver behavior. Furthermore, since it's declared directly in the body of the Subscription class (rather than a value that gets assigned to the property) it's also part of the Subscription prototype and not part of the subscription object itself. Since it's shared across all instances, this can't refer to any specific instance but must look at the receiver.

What happens to 'this' when it goes into Object.map

Does anyone know what happened to 'this'?
console.log('check 1', this) //{activateLasers: ƒ, …}
Object.keys(modelData).forEach(function(key, index1) {
console.log('check 2', this) //undefined
The context of this changes inside map.
Array.prototype.map() takes a second argument to set what this refers to in the mapping function.
You can explicitly pass it to the map function to preserve the context.
array.map(function(i) {
...
} , this)
In your case
array.forEach(function(key, i) {
....
}, this)
Alternatively, you can use an ES6 arrow function to automatically preserve the current this context
array.map((i) => {
...
})
It looks like you're writing code in strict mode. this is undefined because that's how the language works.
this in javascript is a syntactic construct. When you call a class or object method you usually do it in a way that looks like obj.method(). The language sees the syntactic pattern with the . and () and makes this obj inside method. If you ever don't see that pattern, (and are not using an => function, it should be a good cue that this might be undefined or window.

Why we don't need to bind the arrow function in React?

We all know that we need to bind function in React to make it work. I do know why do we need to bind it.
But I'm not sure why we don't need to bind arrow function.
Example:
Using arrow function (No bind in required)
handleClick = () => {
this.setState({
isToggleOn: !this.state.isToggleOn
});
};
Now, Using function (Bind is required)
this.handleClick = this.handleClick.bind(this);
handleClick() {
this.setState({
isToggleOn: !this.state.isToggleOn
});
};
I'm not asking why we need bind in function. I just want to know why binding is not required in arrow function.
Thanks.
Simply because arrow function does not have the following in its context:
this
arguments
super
new.target
So when you reference this inside an arrow function it treat this as any other variable and look for its declaration in its scope first and it can not find it so it search the upper scope which is the this referring to the react component class which what is required so we do not need to bind the this to the class.
To quote MDN:
An arrow function expression has a shorter syntax than a function
expression and does not have its own this, arguments, super, or
new.target. These function expressions are best suited for non-method
functions, and they cannot be used as constructors.
Further,
Until arrow functions, every new function defined its own this value (based on how function was called, a new object in the case of a constructor, undefined in strict mode function calls, the base object if the function is called as an "object method", etc.). This proved to be less than ideal with an object-oriented style of programming.
So basically, the reason we don't need to bind is because this does not exist in the context of the arrow function. So, it goes up to the next level and uses the this it finds there.

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