I'm new to react coming from a .Net background and I was trying to create a class, I tried numerous ways of doing so but in this instance I was unable to create a constructor in this variation and came to the conclusion that this maybe isn't a class, I've searched around the web but haven't found any info
Here is an example:
export default ViewTestStuff => {
constructor(){
// errors
}
return (
<div>
<p>Hello</p>
</div>
)
}
so my question is what is the "=> {}" in this example, is this a class? and why can't I create a constructor in it if it is indeed a class
It is a Arrow Function from es6, and has nothing to do with React.js
const add = (a, b) => a+b;
it is just a function.
calling add(2, 3) returns 5
One important thing to remember is, that arrow functions do not have the prototype chain. You also cannot call them with new.
Another thing to notice is, that this is bound to the context where the arrow function is defined.
const obj = {
name: "Lukas",
method: function() {
var self = this;
console.log(this.name === "Lukas");
return [
function() {
console.log(this !== self)
},
() => {
console.log(this === self)
}
];
}
}
const [func, arrow] = obj.method();
func();
arrow();
see the docs
It is an arrow function! A nice feature on ES6, that is already implemented on most modern browsers.
Something => {} Means a function with Something as it's parameter and an empty body. It is similar to:
function (Something) {
}
In your case, it's the same as:
export default function (ViewTestStuff) {
constructor(){
// errors
}
return (
<div>
<p>Hello</p>
</div>
)
}
And it's indeed invalid.
This is not a React thing... arrow functions are new in es6 javascript. More info can be found here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
Related
What is the difference between class method, class property which is a function, and class property which is an arrow function? Does the this keyword behave differently in the different variants of the method?
class Greeter {
constructor() {
this.greet();
this.greet2();
this.greet3();
}
greet() {
console.log('greet1', this);
}
greet2 = () => {
console.log('greet2', this);
}
greet3 = function() {
console.log('greet3', this);
}
}
let bla = new Greeter();
This is the resulting JavaScript when transpiled from TypeScript.
var Greeter = /** #class */ (function () {
function Greeter() {
var _this = this;
this.greet2 = function () {
console.log('greet2', _this);
};
this.greet3 = function () {
console.log('greet3', this);
};
this.greet();
this.greet2();
this.greet3();
}
Greeter.prototype.greet = function () {
console.log('greet1', this);
};
return Greeter;
}());
var bla = new Greeter();
My TypeScript version is 3.4.5.
There are differences between all 3 versions. This differences are in 3 areas:
Who is this at runtime
Where the function is assigned
What is the type of this in typescript.
Lets start with where they work just the same. Consider this class, with a class field:
class Greeter {
constructor(private x: string) {
}
greet() {
console.log('greet1', this.x);
}
greet2 = () => {
console.log('greet2', this.x);
}
greet3 = function () {
// this is typed as any
console.log('greet3', this.x);
}
}
let bla = new Greeter(" me");
With this class all 3 function calls will print as expected: 'greet* me' when invoked on bla
bla.greet()
bla.greet2()
bla.greet3()
Who is this at runtime
Arrow functions capture this from the declaration context, so this in greet2 is always guaranteed to be the class instance that created this function. The other versions (the method and function) make no such guarantees.
So in this code not all 3 print the same text:
function call(fn: () => void) {
fn();
}
call(bla.greet) // greet1 undefined
call(bla.greet2) //greet2 me
call(bla.greet3) // greet3 undefined
This is particularly important when passing the function as an event handler to another component.
Where the function is assigned
Class methods (such as greet) are assigned on the prototype, field initializations (such as greet2 and greet3) are assigned in the constructor. This means that greet2 and greet3 will have a larger memory footprint as they require an allocation of a fresh closure each time Greeter is instantiated.
What is the type of this in typescript.
Typescript will type this as an instance of Greeter in both the method (greet) and the arrow function (greet2) but will type this as any in greet3. This will make it an error if you try to use this in greet3 under noImplictAny
When to use them
Use the method syntax if this function will not be passed as an event handler to another component (unless you use bind or something else to ensure this remains the instance of the class)
Use arrow function syntax when your function will be passed around to other components and you need access to this inside the function.
Can't really think of a good use case for this, generally avoid.
this keyword difference:
In the above all three have same this but you will see the difference when you will pass the method to another functions.
class Greeter {
constructor() {
}
greet() {
console.log(this);
}
greet2 = () => {
console.log(this);
}
greet3 = function() {
console.log(this);
}
}
let bla = new Greeter();
function wrapper(f){
f();
}
wrapper(bla.greet) //undefined
wrapper(bla.greet2) //Greeter
wrapper(bla.greet3) //undefined
But there is another difference that the first method is on the prototype of class while other two are not. They are the method of instance of object.
class Greeter {
constructor() {
}
greet() {
console.log('greet1', this);
}
greet2 = () => {
console.log('greet2', this);
}
greet3 = function() {
console.log('greet3', this);
}
}
let bla = new Greeter();
console.log(Object.getOwnPropertyNames(Greeter.prototype))
If I have in the class -> str = "my string"; and in all the 3 methods I can say console.log(this.str) and it outputs the "my string". But I wonder - is this really actually the same thing
No they are not same things. As I mentioned that greet2 and greet3 will not be on Greeter.prototype instead they will be on the instance itself. It mean that if you create 1000 instances of Greeter their will be 1000 different method(greet2 and greet3) stored in memory for 1000 different instances. But there will a single greet method for all the instances.
See the below snippet with two instances of Greeter()
im trying reactjs and i got an undefined and i dont kow why.
The code is really simple but maybe i didnt get something ?!
isMailValid(mail) {
const valid_mail = RegExp("[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*#(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?");
console.log("res => " + valid_mail.test(mail));
return valid_mail.test(mail);
}
isMailOk() {
var res = this.isMailValid(this.state.mail)
if (res === true)
return (<p class="false">invalid mail</p>);
return (<p class="good">Mail Ok</p>);
}
I got 'isMailValid' is not defined no-undef.
Thx for help
The function is undefined because it is not in the same scope as the function calling it. To access it you'll have to prefix the call with this. to tell React where to find the function.
isMailOk() {
if (this.isMailValid(this.state.mail) === true)
return (<p class="false">Mail invalid</p>);
return (<p class="good">Mail Ok</p>);
}
You'll also have to bind your custom function to this. You can do that by placing this.isMailOk = this.isMailOk.bind(this); in the constructor. You'll have to do that with both of your custom functions. Functions such as render don't require being bound to this because they are inherited when you extend your class from React.Component. You can read more about binding to this in the docs.
I'm using React and Redux. I have a question. I know when I need "this" in a function I should bind it. But without binding my code works. Why ?
Function :
onSubmit() {
this.props.dispatch({type: 'ADD_TO_LIST', payload: this.state.inputValue});
}
And this is my render input :
<input type="text" placeholder="Enter Your Text ..." onChange={(e) => {
this.setState({inputValue: e.target.value})}} onKeyDown={(e) => {
if (e.key === 'Enter') {
this.onSubmit()
}
}}/>
You have idea about "when binding is required", but you missed one thing, "calling function will have the this (object by which it was called)". The value of this is determined by how a function is called.
Here:
this.onSubmit()
You are calling submit with this (class instance), so this (inside submit) will refer to class instance.
Check these references:
MDN Doc
Why is JavaScript bind() necessary?
Because you used an arrow function to call it, it's not the event handler itself. The arrow function is already bound correctly.
While function is binding (it changes this), ES6 arrow functions are non-binding. An example:
this.a = 1;
obj = {
a: 2,
bfunction: function() { return this.a; },
barrow: () => { return this.a; },
}
console.log(obj.bfunction()) // 2
console.log(obj.barrow()) // 1
When I click on the button [Add to Cart] I'm getting an error:
.
How should I fix that?
Here's my full code link, and below is an abstract, that is relevant to question:
class ProductsList extends Component {
....
renderProductsList() {
function mapProductCards(elem) {
return (
<Card className="m-1" style={{width: '18rem'}} key={elem.id}>
....
<CardText>isAvailable</CardText>
<Button onClick={() => this.props.addItemToCart(elem.id)}>Add to Cart</Button>
</CardBlock>
</Card>
)
}
....
this.props.products ....
.map(mapProductCards)
....
const mapDispatchToProps = (dispatch) => ({
....
addItemToCart(value) {
dispatch(addToCart(value));
}
....
});
export default connect(mapStateToProps, mapDispatchToProps)(ProductsList);
....
At the start of your renderProductsList function, assign your this variable to a local one. Like this:
renderProductsList() {
var that = this;
function mapProductCards(elem) {
return (
and then just use that where needed. For example, your button would now be:
<Button onClick={() => that.props.addItemToCart(elem.id)}>Add to Cart</Button>
Alternatively, use an arrow function instead. Like this:
renderProductsList() {
mapProductCards = (elem) => {
return (
this will preserve the reference of this to the object you actually need.
EDIT
After looking at your full code, based on how you use your mapProductCards function, you need to pass in the correct object to use as this. You can pass that object as the second parameter to your map. Like this:
this.props.products.map(mapProductCards, this);
You might find the documentation for map()over at MDN interesting:
var new_array = arr.map(function callback(currentValue, index, array) {
// Return element for new_array
}[, thisArg])
thisArg: Optional. Value to use as this when executing callback.
I also faced this issue and the problem was when i debugged my code ,local this ie this object of the function was giving undefined object.you need to instantiate this object of the function addItemToCart because when you click the button it will give you an error on console saying
Your method addItemToCart is undefined
to overcome this you need to define local this as
renderProductsList() {
var localThis= this;
}
and then call your method as
onClick={() => localThis.props.addItemToCart(elem.id)}
If you are using a function inside a loop say map then you need to do
this.state.map(function(){
},**this**)
to preserve this
I'm writing an application using angular and typescript.
I'm using ng-grid and I have to handle the afterSelectionChange event.
I tried to set the event handler in two ways
this.$scope.settoriGridOptions.afterSelectionChange = this.afterSelectionChange;
where this.afterSelectionChange is a method of the controller class,
and
this.$scope.settoriGridOptions.afterSelectionChange = (... ) => {};
including the code inside, but in both cases the this pointer is incorrect and I cannot access to the services of the controller.
how can I fix this?
after a more tests and reading a few articles I see that the problem is the implicit passing of the this pointer as parameter in the function call.
if I write
$scope.filtroSoluzione = this.filtroSoluzione;
when called the this pointer is set to null, but if I write
$scope.filtroSoluzione = () => { return this.filtroSoluzione() };
or
$scope.filtroSoluzione = () => { .. inline code ... };
the this pointer I set correctly.
How can I have a more consistent behavior? I don't like to write always the code inside because this makes the class harder to read and navigate
thanks,
Luca
Thanks for the extra information in your edits, I now see the problem.
class foo {
public afterSelectionChange = () => {
console.log(this);
}
}
When you declare your function like I did above, your this is the instance instead of what you are seeing know because it captures the this variable. It comes with a cost though, because now it creates a new afterSelectionChange function for every instance of your class. In this case I think it is still what you want though.
var foo = (function () {
function foo() {
var _this = this;
this.afterSelectionChange = function () {
console.log(_this);
};
}
foo.prototype.baz = function () {
console.log(this);
};
return foo;
})();
In the above code-gen you can see the difference when declaring the function with name = () => {} and the normal way.
Another solutions might be this:
this.$scope.settoriGridOptions.afterSelectionChange = this.afterSelectionChange.bind(this);
But I don't find that really nice either... (this should work with the normal public afterSelectionChange() {} declaration you are used to.