Still not understanding .this after reading articles - javascript

I'm a JS/React beginner who has read a few articles on the this keyword on JS, but remain confused.
Namely, I've consulted Tyler McGinnis's React and The Complete Javascript on Udemy.
This keyword is a fairly complex topic imo, but from these two sources I know .this refers to the global scope by default, but refers to the object in question when it is defined within a method. I also know that .call/apply/bind can give us a hint on what the .this refers to.
My question is, when do you actually write the .this keyword when you are writing your programs? The sources above seemed to focus on understanding why others might've used the keyword, but not necessarily when you need to do it. Thus, I always get confused when tutorials seemingly randomly throw in a this/bind etc everywhere
In terms of specific examples, I have :
1. One in the context of states:
I've encountered apps before learning about the .this concept which do not use the .this keyword. No specific examples for this, but shouldn't you use .this most of the time then?
Apologies if this is a silly question -- sometimes I wonder whether it is better to analyze/dissect the rationale for each part in coding or just to learn coding as just the way things are much like a child learns a language naturally without questioning grammar rules
In this example, we are passing down a prop called onDelete, but I do not understand why we need to bind. Does this mean we are binding the passed down onDelete to props.id which was also passed down?

The important part is you took the time to research. Personally I do not recommend using React to learn about this. When you extend a React component, your this prototype inherits from React.Component, so there's a lot of React-specific conventions there already. Instead, consider this example where I call this directly
function SimpleQueue({ size }) {
this.size = size
this.buffer = []
}
SimpleQueue.prototype.push = function(item) {
this.buffer.push(item)
if (this.buffer.length > this.size) {
this.buffer.shift()
}
return this
}
SimpleQueue is just a simple queue implementation using an internal array. You can think of this as a reference to the current instance of SimpleQueue, whatever that may be. I use this specifically in the example above to access the internal array as this.buffer. I can then use an instance of a SimpleQueue like so
const mySimpleQueue = new SimpleQueue({ size: 3 })
mySimpleQueue.push(1) // SimpleQueue { 1 }
mySimpleQueue.push(2) // SimpleQueue { 1, 2 }
mySimpleQueue.push(3) // SimpleQueue { 1, 2, 3 }
mySimpleQueue.push(4) // SimpleQueue { 2, 3, 4 }
Note: my example does not use class, but it is the same because classes are syntactic sugar for the prototype-based programming model

shouldn't you use .this most of the time then?
Yes, for class based react components, you should almost everywhere use this., for access props, state, handlers, calling methods etc.
constructor is an exception ... this.state is created, props are constructor argument.
Handlers declared using handleChange(e) {} syntax needs .bind(this) to be able:
to operate on this.state;
to use this.setState() (react component method derived from base class);
to use other methods defined in this component.
Usually event handlers are binded in constructor in the form like:
this.handleChange = this.handleChange.bind(this);
<button onClick={this.handleClick} />
Event handlers defined using ES6 'arrow syntax' fn = () => {} are autobinded to this.
Also handlers defined using 'normal function syntax' but assigned using 'arrow syntax' in render doesn't need binding:
<button onClick={(e) => this.handleClick(e)} />
Bad news - every render call crates new ref ... at least not optimal in react ... so ... use arrow declaration (or bind in constructor).
we are passing down a prop called onDelete, but I do not understand why we need to bind
Why? Probably passed handler not binded - rare requirement to bind handler to different object/component context (different this).

"this" is not a complex topic. people make it complex.
you have
handleTitleChange=(title)=>{
this.setState({})
}
When you say this.setState() you want this to refer the class component that you defined the handleTitleChange() inside. Arrow functions AUTOMATICALLY allow you to set “this” when the function is defined. That is why it is said that arrow functions are lexically bound to this. When our component is getting rendered by javascript for the first time, it checks inside and sees that there is handleTitleChange() points to arrow function. The moment it sees “this”, it is going to automatically bind “this” to the place where the arrow function is defined in the the first place. The context of that function is the TimerForm component.
But by default javascript does not set its scope of “this” on functions. "this" is dynamically scoped, it does not matter where the function is written, it matters how the function is called. That is why we have to actually explicitly state what context you want “this” to be for us. We want “this” to be our class component and the method in which we can do it is to define in our constructor(). If you write above code like this :
handleTitleChange(title){
this.setState({})
}
Now,in the above function this refers to the class but when you pass the reference to be called by another component or function, you are not passing its "this" anymore. New "this" will be assigned by object which calls "handleTitleChange(title)". We have to make sure that when we call handleTitleChange(title), its "this" value always points to TimerForm class. So we go to constructor(){}. Because our constructor() is the code that runs first before anything gets called. We want to make sure that the context of this is correct in all of our methods before any code gets written.
constructor(){
super()
console.log(this) // it will log TimerForm class
this.handleTitleChange=this.handleTitleChange.bind(this)
//bind(this) `this` refers to the TimerForm
}
bind() is a method on any function that returns a new function with a new execution context. now our handleTitleChange method learnt that this inside of it, will refer to the TimerForm class component.

to your 3rd question. props.onDelete is a function that's passed down, it's binding on this, which is the current execution context in <TouchableOpacity>, props.id is the argument of the onDelete function.
this is the old way, I believe an arrow function will do the same thing, () => props.onDelete(props.id)
And in react world/javascript land, function components/object destructing/arrow function are taking more ground these days, might be a reason you see less/none this in the codebase.

Related

In React why is the render method bound to component instance but not custom methods?

In a class, why is the render method automatically bound to the component instance but custom methods e.g. event handlers aren't?
I understand using the bind keyword to make these event handlers work but was just trying to find an answer why "this" can be referenced in the render method but why it's also not automatically bound in event handler methods?
why is the render method automatically bound to the component instance
It isn't bound. It's just that react always calls the render function using the correct context.
For normal functions, the value of this is determined by how you call the function. In the following code, example. is the part that says what the value of this will be inside the function.
const example = {
value: 'abc',
printValue: function () {
console.log(this.value);
}
}
example.printValue(); // abc
But if you call the function in a different way, you can get a different value of this.
const example = {
value: 'abc',
printValue: function () {
console.log(this.value);
}
}
const temp = example.printValue;
console.log(temp === example.printValue); // true (they're literally the same function)
temp(); // undefined, or throw an exception depending on if we're in strict mode
So every time react calls the render function, it calls it the first way (or something equivalent to it), not the second way.
Citing React's docs:
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.
Defining them as arrow functions though, still at instance level, will change the scope to the component's instance. So all other methods like render, componentDidMount are part of the class' definition and are not event handler, which means this will point to the instance in them (the usual JavaScript behaviour for such methods).
And lastly, you can always call a method with a different scope with apply or call, changing what this refers to in those methods.

How does 'this' work in Lifecycle methods?

I'm new to react js and have been reading the react docs. In one of the examples, a property (this.timerID) is defined within a lifecycle method (and not in the constructor) and it goes on to be used in another method. I'm having trouble understanding how 'this' in the property helps increase its scope.
The exact document is on, https://reactjs.org/docs/state-and-lifecycle.html. I have been conducting further research about 'this' on https://www.codementor.io/dariogarciamoya/understanding--this--in-javascript-du1084lyn?icn=post-8i1jca6jp&ici=post-du1084lyn. I don't know if its my understanding of ES6 class methods or 'this' that is causing a problem.
class Clock extends Component {
constructor(){
...
}
componentDidMount(){
this.timerID = setInterval(() => this.tick(), 1000)
}
componentWillUnmount(){
clearInterval(this.timerID);
}
}
Apologies if the question is a bit vague, and any help is appreciated.
this refers to the current instance of the component. So in your example you are setting the interval to your instance.
when you use this keyword with a variable or object then it is referred under the present scope of it. Here the ComponentDidMount is a class lifecycle method and when a variable is assigned with this keyword inside any method of a class, then it means that it is accessing the variable of the Class rather than its own variable.
Here, in your example, the this.timerID variable is used by ComponentDidMount in the scope of the entire class to change the state variable and then render the component. If you use var timerID in ComponentDidMount then it will work as same but if you want to use timerID in other functions then this.timerID will show as undefined as it will only available when mounting and its scope in only inside that method.
The thing is that the everything you are using must have a defined scope.
Here, this keyword just elaborated the scope for the variable to be used inside the class. Thats it, there are just proper ways to manage the variables/objects to get your work done.

why should I use bind(this) with a method in a class?

Given the documentation
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.
I'm currently following a tutorial about creating a blockchain using node.js
https://developers.caffeina.com/chiccocoin-learn-what-is-a-blockchain-by-creating-one-in-nodejs-12929a89208b
But what I don't understand in the following example (code provide by the tutorial I'm following) is why should I bind the keyword 'this' to a method which belong to a class. Given the function newBlock() belong of the class Blockchain, it should have access to the 'this' and all of the variable related to the class Blockchain.
class Blockchain {
constructor () {
this.chain = []
this.newBlock = this.newBlock.bind(this)
this.newBlock(100, 1)
}
newBlock (proof, previousHash) {
const block = this.chain.length + 1
}
}
Does anyone can explain me why should I use bind(this) with a method in a class ? Actually it may be possible that I misunderstood the purpose of bind(this) so that would be great if you could point me out what did I misunderstand.
Thanks :)
Bind will create a copy of the function which will guarantee that the reference of "this" in function newBlock will point to Blockchain. If a new function (let's call it function readBlocks) were to invoke newBlock, it's this context would instead point to readBlocks instead of Blockchain. Binding will allow you to use newBlock without worrying about it's this context being dynamic.
class definition the way you did, in javascript, is still doing prototypal inheritence behind the scenes. This class definition is malleable and you can add more methods to it by just adding more methods to it's prototype. So the class syntax is more like syntactic sugar (not completely, but for most practical purposes) for the normal prototypal inheritence done using functions.
Given that background, this binding in javascript was always done at runtime (except for arrow functions). The context in which a particular method is called determines the this binding. It's not bound at the time of defining the method. But that rule does not hold if you prebind the method to a particular context, like you did in your example with .bind.
If you had not done that, someone could have called the method newBlock like this
let a = new Blockchain()
let b = new Blockchain()
a.newBlock.call(b, proof, previousHash)
And since binding of this is done at runtime, in the above case, the method newBlock will be called with this refering to object b. But that will not happen if you prebind the method using .bind.
It's tricky. But main takeaway is that the runtime binding rules of this in javascript still hold for the new class syntax. Hope it helped.

In the following example of React ES6, how is it possible for an object property referenced w/o the 'this.state'?

I pulled this example from a tutorial I was following. I am perplexed with the situation where the selectedGif property is able to refer to "selectedGif" w/o "this.state" as required by other property references such as "this.state.gifs." Is that rule an exception when an arrow function is applied?
The onGifSelect inline event handler is not referencing selectedGif from this.state.
It is being passed an anonymous function written using ES6 arrow function notation.
So:
selectedGif => this.openModal(selectedGif)
is nearly equivalent to:
function(selectedGif) {
return this.openModal(selectedGif);
}
// NB: Using the latter to invoke `openModal` will THROW AN ERROR
// because `onModal` is invoked within the inline event handler
// '`onGifSelect`' and **not** the component scope/context.
// The result is that the `this` within `onModal` refers to the
// inline event and not the component context `this` where `setState` exists.
There are a couple of ways to get around the above issue:
using .bind()
OR
Using the arrow function (=>) syntax remedies this because:
arrow functions do not create their own scope/context so invoking this.setState within openModal will work as expected.
It's not referencing this.state.selectedGif. It kind of looks like it, but it's just referencing a variable in an anonymous function that could have gone by any other name. The above code would behave precisely the same written like
onGifSelect={foo => this.openModal(foo)}
aka
onGifSelect={(function(foo) { this.openModal(foo) }).bind(this)}
But this function isn't making any use of its argument rather than pass it along. It would be better written as
onGifSelect={this.openModal}
without the extra wrapping function that only serves to retain the surrounding context. Would be better to bind the function in the constructor or use class arrow notation if you have stage-2 enabled https://github.com/tc39/proposal-class-public-fields

Dynamically superseding functions that are not in global scope

I have a script, that based upon specific scenarios, may need to supersede functions to do some processing before eventually calling the original function. (See "'overriding' Javascript Function")
I can get this working in general - here's a basic example using the jQuery plugin Tinyscrollbar (not my intended application, just something quick and easy to illustrate):
(function ($) {
// Snip..
function initalize() {
oSelf.update();
setEvents();
return oSelf;
}
// Snip..
function setEvents() {
(function () {
var oldInit = wheel;
wheel = function (oEvent) {
console.log('Intercept');
oldInit(oEvent);
}
})();
// Original event code, irrelevant to question
}
function wheel(oEvent) {
// Actual function, related to using the mousewheel
}
})(jQuery);
When I scroll the mousewheel, the console prints 'Intercept', and the scrollbar moves as originally defined. Wonderful!
However, the function name is hardcoded, and doesn't live in the global scope, so window[] is unavailable (which I like). Is there any possible combination of black magic, 'new Function()', and/or other way to loop through a potential list of function names (which may change based on other logic) and encapsulate them in this (or similar-in-spirit) manner?
Thanks in advance!
Unfortunately, there's no way to enumerate or dynamically access members in a scope object (with the convenient exception of the global scope/window object)
So you'd need to rephrase your code a bit. Instead of having free-floating functions in your outer function, have objects with methods on them. That'd make replacing those methods much easier.
There's some additional trickiness if you modify your functions after you started assigning them as event handlers or whatever. If you happen to use some kind of bind() wrapper around those functions, the correctness of your behavior will depend a lot on that bind() function.
Specifically, if you want the replacement method to retroactively become the method called for any event handler or callback it was assigned to, you'll want to use a bind() wrapper that takes a context object and a string meant to be the function name rather than a context object and a function reference. (and make sure that bind() doesn't resolve that string early to shave some ms on each calls.)
If don't don't want the retroactive behavior, you still have to make sure you don't have some bind()-ed version of the original method floating around and still being used for new callbacks after your replacement happened.

Categories