Whats the difference between functions declared with const and functions declared without let or const and a function declared otherwise in an ES6 class?
class App extends Component {
submitFood = () =>{
// some code
}
Why does the above work OK but the declaration below give an error:
class App extends Component {
const submitFood = () =>{
// some code
}
First of all: None of the examples you provided is valid ES6. The grammar rules for ES6 classes only allow methods definitions inside the class body. I.e.
class MyClass {
method1() {}
method2() {}
}
The first example however is making use of the class fields proposal. This proposal extends the existing grammar to allow the definition of properties of the form
class MyClass {
someProperty = value;
}
These assignments are not evaluated at class definition time but at instantiation time. It's syntactic sugar for assigning properties in the constructor:
class MyClass {
constructor() {
this.someProperty = value;
}
}
Your second example is simply invalid syntax because there are no grammar rules that allow putting let or const before the class field.
Keep in mind that class fields are not variable declarations or variable assignments.
const submitFood = () =>{
// some code
}
Is the creation of function (submitFood=() {}) and the creation of a variable so usual rules in variable hosting blocked let and const.
so fail since submitFood() is not defined. (It will throw a ReferenceError).
Related
I would like to have a class with some constants, so I can make calls such as:
const MyClass = require('./myclass.js');
console.log(MyClass.CONST1);
console.log(MyClass.CONST2);
let a = new MyClass();
...
My problem: I have to define a large amount of constants, so I would like to have a distinct block of code where the constants are defined, apart from my class definition:
a stand-alone object which defines the constants
the class definition
... And afterwards, merge them together into a single class definition so the caller use the constants as if they were part of the class definition.
Here is the way I found to do so, but I don't know if this is correct or if it could lead to some problems:
myclass.js
const MYCONSTANTS = {
CONST1: 1,
CONST2: 2
};
class MyClass {
constructor() {
}
}
// "merge" constants into MyClass
let exportedClass = Object.assign(MyClass, MYCONSTANTS);
// freeze exportedClass in order to forbid any change in constants values
Object.freeze(exportedClass);
// export
module.exports = exportedClass;
It seems to work, but I am not sure the way I "extend" the class is correct: I manipulate MyClass as if it was a variable (with Object.assign). Maybe there is a better/safer way to achieve this ?
If I write a React class like this:
class SomeClass extends React.Component {
state = {
someState: this.someRegularFunction(),
someOtherState: this.someArrowFunction()
};
someRegularFunction() {
return "someText";
}
someArrowFunction = () => {
return "someOtherText";
};
}
Webstorm code assistance warns about the calling of arrow function this.someArrowFunction() saying:
Field 'someArrowFunction' is declared after 'state' and is possibly
not assigned yet
If does not warn about the call of the regular function this.someRegularFunction().
And Webstorm is correct, the execution fails when calling this.someArrowFunction() with:
TypeError: _this.someArrowFunction is not a function
I've been looking for some documentation explaining this behavior, but have been unable to find any.
Why can you call regular functions, but not arrow functions, before their declaration inside a class?
Because that code is functionally identical to this:
class SomeClass extends React.Component {
constructor(...args) {
super(...args);
this.state = {
someState: this.someRegularFunction(),
someOtherState: this.someArrowFunction()
};
this.someArrowFunction = () => {
return "someOtherText";
};
}
someRegularFunction() {
return "someText";
}
}
Field definitions are processed in source code order, when the instance is created. It's as though they were inserted into the constructor before any other code (in a base class) or just after the call to super (in a subclass).
In contrast, someRegularFunction is a method of the prototype, which is created when the class definition is evaluated, not later when the instance is created.
This is covered by the proposal for the class fields feature, in the specification text. (Reading spec text is not for the faint-hearted, though! :-) )
Side note: It's arguably a matter of style, but if you're doing that arrow function so that it can use this without your worrying about how it's called (for instance, as an event handler), you might consider making it a method and then using bind in the constructor (or effectively in the constructor) instead:
class SomeClass extends React.Component {
someFunction = this.someFunction.bind(this);
state = {
someState: this.someRegularFunction(),
someOtherState: this.someFunction()
};
someRegularFunction() {
return "someText";
}
someFunction() {
return "someOtherText";
}
}
That plays more nicely with testing code that may need to mock the function (by replacing it on the prototype).
But again, it's arguably a matter of style.
Is there any reason to write classic syntax of ES6 methods?
class MyClass {
myMethod() {
this.myVariable++;
}
}
When I use myMethod() as callback on some event, I must write something like this (in JSX):
// Anonymous function.
onClick={() => { this.myMethod(); }}
// Or bind this.
onClick={this.myMethod.bind(this)}
But if I declare method as arrow function:
class MyClass {
myMethod = () => {
this.myVariable++;
}
}
than I can write just (in JSX):
onClick={this.myMethod}
The feature you are using is not part of ES6. It's the class fields proposal. It allows you to initialize instance properties without having to write a constructor. I.e. your code:
class MyClass {
myMethod = () => {
this.myVariable++;
}
}
is exactly the same as
class MyClass {
constructor() {
this.myMethod = () => {
this.myVariable++;
};
}
}
And this also shows you what the difference is between a normal class method an a method created via a class field:
A normal method is shared between all instances of the class (it is defined on the prototype)
A "class field method" is created per instance
So all the same as reasons as presented in Use of 'prototype' vs. 'this' in JavaScript? apply, but in short:
Use "class field methods" if you need a method per instance. Such is the case for event handlers that need to access the current instance. Access to this also only works if you are using an arrow function.
Use normal class methods in all other cases.
I'm trying to get my head around the scope of functions. _internalFunction works well, but how do I call _externalFunction instead?
I've tried self=this and then this._externalFunction inside _renderRow and also tried () => {this._externalFunction} but it didn't work.
class sandbox extends Component {
//some code removed for clarity
_renderRow(item) {
const _internalFunction = () => {
Alert.alert('Internal');
};
return (<Text onPress={_internalFunction}>{item}</Text>);
}
_externalFunction() {
Alert.alert('External');
};
}
Here's the code in React Native Playground to fiddle with:
https://rnplay.org/apps/5CIGvA
Thanks in advance! :)
In ES6 you need to manually bind this to the instance. Here is a quote from React documentation:
In React components declared as ES6 classes, methods follow the same
semantics as regular ES6 classes. This means that they don't
automatically bind this to the instance. You'll have to explicitly
use .bind(this) in the constructor:
Therefore you need to bind your function in constructor:
constructor() {
super();
this._externalFunction = this._externalFunction.bind(this);
}
And then you can use this._externalFunction in your component:
_renderRow(item) {
return (<Text onPress={this._externalFunction}>{item}</Text>);
}
I'm trying to adapt code from a SO answer, with functions and variables written as below:
const getIntervals = n=> availability=> {
}
let availability = [
]
Are those normally fine to use in a react class (see below) or do they need to be rewritten?
class Calendar extends React.Component {}
The reason for asking is that I use a React implementation for Rails and do get an error including that function and variable naming pattern.
Pure Functions, which dont modify the passed value, are always fine to use anywhere.
Its also fine to use them in a React Class directly, but common functions like string modifications, array sorting algorithms, which you are using a lot across your app and classes should go in a separate module like
// my-helpers.js
export const countKeysInObject = (data) => {
if (typeof data !== "object" || Array.isArray(data)) return 0;
Object.keys(data).length;
}
some other file..
import { countKeysInObject } form 'my-helpers'
// And you can use it everywhere..
If you are using class and extending Component, you can use simple methods for most things:
class Calendar extends React.Component {
constructor(props) {
this.date = props.date;
}
render() {
return <span>{this.date.toString()}</span>;
}
}
Calendar.propTypes = {
date: React.PropTypes.date.isRequired
};
You cannot use methods for propTypes or anything that would be an initial field if you were using an object literal. Those need to be attached after the class has been declared (propTypes) or in the constructor (initial state).