React Questions - javascript

Am I wrong if I explain the provided example like this :
once the component loads, the first button will be clicked automatically because this.handleClick1 was called by adding the bracket.
If you click the second button, there will be an error because you are using an es5 function and the "this" keyword behaves differently in an ES5 function compared with the arrow function or ES6 function. In ES5 function, the "this" keyword refers directly to the object that contains it and in this case the object that contains it is the which is an object and so there is an error because the button object does not contain a handleClick1 property. To fix this problem, you have to either use an ES6 function to declare the handleClick1 function or if you must use the ES5 function then you have to bind the function to the class

The first button is not clicked immediately. You are calling the handler function immediately instead of assigning it as the handler.
Arrow functions and .bind() act similar in that they statically bind this for that function.
However, React.Component won't statically bind methods to itself. If you (properly) set a button onClick to a component method, the context will change. To fix this somewhat unexpected behavior you will need to use arrow functions or .bind() in the constructor.
Keep in mind that if you were to call handleClick1() from inside your component (as you do when improperly setting the first button handler) this will be what you expect it to be. Thats just how this works.
Here's a sandbox for anyone interested: https://codesandbox.io/s/react-playground-forked-nimby?file=/index.js

Related

What is the correct way to set state in React

Honestly, this is my day 1 in ReactJS. I'm learning some small-small things like state. I've created a small program for the toggle button. It will simply display "Hello world!" or display nothing when the button is toggled. There's one thing that I didn't understand. My code gives me an error when I use this syntax:
toggleHandler() {
const currentStatus=this.state.display;
this.setState({
display: !currentStatus
})
}
this.state is undefined
But the same code works perfectly If I change the syntax to a fat arrow function:
toggleHandler=()=> {
const currentStatus=this.state.display;
this.setState({
display: !currentStatus
})
}
I'll not waste your time. I've created an stackblitz. Experts on the internet say that any call to this.setState() is asynchronous. So I tried using call back function and IIFE but got myself more confused and over-complicated. Please correct me. I'm sorry this is a very childish question.
There are a couple of ways.
One is to add in the constructor. ES6 React.Component doesn't auto bind methods to itself. You need to bind them yourself in constructor. Like this
this.toggleHandler = this.toggleHandler.bind(this);
Another is arrow functions toggleHandler = (event) => {...}.
And then there is onClick={this.toggleHandler.bind(this)}
reference
What the error message is telling you is that the this object doesn't contain a property called state. What exactly this refers to is a constant source of confusion in JS, except when inside an arrow function. Inside an arrow function, this always refers to the context the arrow function appears in.
The issue here is in the first example, this refers to the context sent to the handler by the onClick event. This context does not contain a state property. However, inside the arrow function, the this keyword will refer to the JavaScript class that your arrow function exists in. This class does have the state property.
To get around this, you can use bind (which outputs a copy of your function with the context set to whatever you supply it with. Or just use arrow functions. If it were me I would take the latter approach since this has better defined and more consistent behaviour inside an arrow function. If you do want to use bind, you would do this in your event handler declaration like so:
onClick={this.toggleHandler.bind(this)}
The way you can use functions and previous state.
1- Binding in constructor
constructor() {
this.toggleHandler=this.toggleHandler.bind(this);
}
can define like this
toggleHandler=()=>{
this.setState(prev=>({
display: !prev.display
}))
}
2- arrow function (don't need to bind in constructor)
toggleHandler=()=>{
this.setState(prev=>({
display: !prev.display
}))
}
3- Inline binding
<Button onClick={this.toggleHandler.bind(this)}>Toggle</Button>
function code
toggleHandler=()=>{
this.setState(prev=>({
display: !prev.display
}))
}
4- Inline arrow function
<Button onClick={()=>this.toggleHandler()}>Toggle</Button>
function code
toggleHandler=()=>{
this.setState(prev=>({
display: !prev.display
}))
}
Note - Recommended to avoid inline functions for better performance
Yes, any setState call is asynchronous. You can check your log that it changes his status but not manipulate the dom. For manipulating the dom Any asynchronous call should be via a callback function.
you can bind any state with this arrow function or this.state.bind(this).

jQuery using on and bind in the same call

I ran into this code and am not sure how it works:
options.on('change', this._onBundleOptionChanged.bind(this));
this._onBundleOptionChanged is simply a function that takes one paramter, event:
_onBundleOptionChanged: function onBundleOptionChanged(event) {
jQuery version is 1.12.4.
the bind call returns function bound() whatever that means and if bind is passed a single parameter it has to be an object the documentation says "An object containing one or more DOM event types and functions to execute for them." here: http://api.jquery.com/bind/
So as I understand what it accomplishes, calling the _onBundleOptionChanged method when a select dropdown is changed.
What I don't understand is how, or why anyone would program it this way.
It is not jQuery's bind.
It is function.prototype.bind (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind).
It is changing the context of the callback function to the be the same as when this statement is executed. This can be very useful.
In most cases, the value of this is determined by how a function is called. It can't be set by assignment during execution, and it may be different each time the function is called. ES5 introduced the bind method to set the value of a function's this regardless of how it's called, and ES2015 introduced arrow functions which don't provide their own this binding (it retains the this value of the enclosing lexical context).
See:
How to access the correct `this` inside a callback?
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this

bind this is optional in class if no constructor?

I have below class, but I'm confused by the bind this here. The class don't have a constructor and super(), why did he need to do bind this on setAll method? I removed the bind this, the application still work and no error.
class PushScheduleActions {
/**
* Request all API
*/
fetchAll(params) {
return dispatch => {
dispatch(params);
PushScheduleApi.getAll(params)
.then(this.setAll.bind(this));//why use bind this here?
.catch(this.setError.bind(this));
}
}
setAll(data) {
return data;
}
}
There is no relation between constructor, super and bind.
What bind does?
it returns a new function with the context user passed.
In your case, PushScheduleApi success case you are passing a new setAll function which is returned by bind method.
since your setAll function doesn't use context, you don't need to pass the context.
dispatch is an arrow function, so context is inherited. So you dont need bind method. you can simply use this.setAll
The class don't have a constructor and super()
That's completely irrelevant.
why did he need to do bind this on setAll method?
The method only needs to be bound if
it uses thisand
this should refer to what this refers to inside fetchAll (likely an instance of PushScheduleActions).
Since setAll doesn't reference this, there is no reason to bind.
However, the whole setAll method is unnecessary. The code would work exactly the same without .then(this.setAll.bind(this)). That makes me think that PushScheduleActions is supposed to be subclassed and child classes are supposed to overwrite setAll. Now, the child class' setAll might use this and expect it to refer to the instance. Since the parent class (PushScheduleActions) can't know that, binding the method is safer since it will ensure that child class implementations of setAll will work regardless if they use this or not.
The bind() function creates a new bound function (BF). A BF is an exotic function object (a term from ECMAScript 2015) that wraps the original function object. Calling a BF generally, results in the execution of its wrapped function.
For more detail follow this link i hope it will help you a lot to understand to bind() method
Use of the JavaScript 'bind' method

About JavaScript bind method

reference code segment
this.localizationChanged = this.localizationChanged.bind(this);
Who can tell me why to write like that?
Who can tell me why to write like that?
localizationChanged is used as event handler:
LocalizationStore.addChangeListener(this.localizationChanged);`
If the handler was not bound to the component instance, this would not refer to the component instance and it wouldn't be possible to call the setState method of the component (this.setState(...)).
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.
from MDN.
If you are trying to access this in localizationChanged function you bind this.
However in ES2015 you don't require this.You can use arrow operator :
localizationChanged =()=>{
console.log(this);
}

Polymer this-pointer

I'm using the Polymer framework and I really enjoy it. But one thing I don't get is the confusion with the this-pointer. When functions get called from for example a button in your custom component the this-pointer points to the custom component. Very logical. But when your function within a custom component is called from something external, for example a callback from an library or a call from another component the this-pointer is something totally different. Why is it in this case not pointing to the custom component where the function is in?
Javascript is a bit of a weird bird when it comes to resolving this, often not doing what you would like. The only saving grace is that it's easy to explain and understand.
A function's this value is set by how it is called. Suppose you have a value val with a method method. If method is called like val.method() then in that call to method then this is val. If you instead do var theMethod = val.method; theMethod(); then for that call, this is something else (the global context object, in browsers this is window).
The solution fortunately is simple. There's a method on functions called bind that returns a new function that has the this immutably baked in. So var theMethod = val.method.bind(val); theMethod() has this bound to val.
In the future for many cases we'll be able to use ES6 Arrow Notation to get this behavior baked in at function definition time, but for now, when passing a method around (e.g. to register an event handler) be sure to bake the this in explicitly with bind.

Categories

Resources