Instance property in React ES6 class

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++
  }
}

Answers:

Answer

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/

Answer

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:

  1. Re-render component when necessary using this.setState().
  2. Force update and re-render the component using this.forceUpdate().
  3. Re-render the parent component.
  4. Change properties from React's lifecycle hook for eg shouldComponentUpdate()

  5. 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))
Answer

The answer is you can, but instead of myField++, change it to this.myField++. An example created on snack @ here

It really has nothing much to do with React but more on general class concept in JS. Find out more about class

Answer

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
  }
}

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.