Reputation: 27852
How come in React you can define state like below:
class Test extends React.Component {
state = { foo: 'bar' }
}
But in order to define other instance properties you need to do it in the constructor or other functions? As in, you can't do this:
class Test extends React.Component {
myField = 0;
render() {
myField++
}
}
Upvotes: 1
Views: 5082
Reputation: 17608
You can do this.myField++
. Though syntax is wrong since you must return something from render like:
class Test extends React.Component {
myField = 0;
render() {
return <div>this.myField++</div>
}
}
You won't see 1
there because React first sees myField's value and render it.
But I think the actual question is not about how we use it. It is about a new proposal for ES: class-fields. Here is an explanation for that: https://stackoverflow.com/a/50789811/7060441
This is a new proposal (class fields) for ES which is in [stage 3][1] right now. To run a code written in this way you need a transpiler like Babel and an appropriate plugin.
Before transpile:
class A { static color = "red"; counter = 0; handleClick = () => { this.counter++; } }
After transpile (with stage 2 on Babel Repl):
class A { constructor() { this.counter = 0; this.handleClick = () => { this.counter++; }; } } A.color = "red";
In addition to the official proposal [2ality blog post][2] is a good source to see what are the details.
Here is a [reddit post][3] if you have time to read the discussion storm what is the reason behind this proposal :)
The arrow function here is a different story. You can use instance properties without constructor and mix your code with standard functions. But when you want to use something like that
this
won't work:class App extends React.Component { state = { bar: "baz"} foo() { console.log(this.state.bar) }; render() { return <div><button onClick={this.foo}>Click</button></div>; } }
We need to bind our function in somehow like:
return <div><button onClick={this.foo.bind(this)}>Click</button></div>
But, binding our function in a JSX prop is no so good since it will create our function in each render.
One way to do this nicely bind in our constructor:
constructor(props) { super(props); this.foo = this.foo.bind( this ); }
But, if I have to write a constructor what is the point? This is why you see arrow functions everywhere where we define the classes like your second example. No need to bind to function thanks to arrow functions. But it is not directly related to this new proposal I think.
[1]: https://github.com/tc39/proposal-class-fields [2]: http://2ality.com/2017/07/class-fields.html [3]: https://www.reddit.com/r/javascript/comments/6q0rov/es_proposal_class_fields/
Upvotes: 1
Reputation: 7545
That syntax is syntactic sugar. Nothing "new" about JavaScript in this regard. It abstracts out the concept of creating a constructor function for the sole purpose of declaring variables within the class
's context and does it for you. These are equivalent:
class Sample {
dog = 1
}
class Sample {
constructor() {
this.dog = 1
}
}
Upvotes: 0
Reputation: 85545
You can do this:
class Test extends React.Component {
myField = 0;
render() {
this.myField++ // use this to access class properties
}
}
But avoid using normal class properties and use state properties like in your first example. So, that you can:
this.setState()
.this.forceUpdate()
.Change properties from React's lifecycle hook for eg shouldComponentUpdate()
Not allow to mutate the property from outside the scope for eg. if you are using normal properties, then you can change it from the browser console.
You might need normal properties like in scenario of:
Set timer as normal class properties in the constructor
this.timer = setTimeout(..)
Clear timer in componentWillUnmount
componentWillUnmount (clearTimeout(this.timer))
Upvotes: 2