user11749073
user11749073

Reputation:

Why is the variable declared in ComponentWillMount Undefined?

I have a component of this type. For simplicity, I have removed all unnecessary code.

This component displays a button when clicking on which the value of the variable I declared in ComponentWillMount should be displayed in the console, but when clicked, the console displays undefined, why?

    'use strict';
    class LoginFormComponent extends React.Component {

      handleSubmit() {
        console.log(this.model); //undefined
      }

      componentWillMount() {
        this.model = 123;
      }

      render() {
                    console.log(this.model);  //123
        var styles = this.props.styles;

        return (
                <CM.MUI.FlatButton
                style={styles.buttonStyle}
                onClick={this.handleSubmit}
                label={CM.gettext('Login')}/>
        );
      }
    };

    module.exports = LoginFormComponent;

Upvotes: 2

Views: 480

Answers (5)

Praveen Kumar Purushothaman
Praveen Kumar Purushothaman

Reputation: 167182

You should be using componentDidMount for setting up the instance properties as the content in componentWillMount will not be in the instance scope as the component isn't mounted yet.

Also, use a => fat arrow function to get the access to this instance of your component.

Updated Code:

class LoginFormComponent extends React.Component {
  handleSubmit = () => {
    console.log(this.model); // 123
  }

  componentDidMount() {
    this.model = 123;
  }

  render() {
    console.log(this.model); //123
    var styles = this.props.styles;

    return (
      <CM.MUI.FlatButton
        style={styles.buttonStyle}
        onClick={this.handleSubmit}
        label={CM.gettext("Login")}
      />
    );
  }
}

export default LoginFormComponent;

Console

preview

Demo: agitated-solomon-3rrow - CodeSandbox

More information

As explained in this demo: summer-violet-g4pyd - CodeSandbox, it looks like the way React works is as follows:

  1. Constructor
  2. componentWillMount
  3. Render
  4. componentDidMount

So after the render() is executed, the componentDidMount is getting executed and there's no change after any state change.

preveiw

If you want something to be there, please put them in constructor().

Moreover, componentWillMount is deprecated and you should not use that in the next releases.

Upvotes: 4

Hesam B.
Hesam B.

Reputation: 65

I think this.modal refers to the FlatButton component instead, can you bind the handleSubmit to LoginFormComponent?


    class LoginFormComponent extends React.Component {
      constructor(props) {
        super(props);

        // This binding is necessary to make `this` work in the callback
        this.handleSubmit = this.handleSubmit.bind(this);
      }
      handleSubmit() {
      ...


Upvotes: 1

Thomas Billot
Thomas Billot

Reputation: 163

First, model seems to be a used as a state field, so as stated in the React docs :

Typically, in React constructors are only used for two purposes:

  • Initializing local state by assigning an object to this.state.
  • Binding event handler methods to an instance.

You should not call setState() in the constructor(). Instead, if your component needs to use local state, assign the initial state to this.state directly in the constructor:

So you should first define your state using:

constructor(props) {
    this.state.model = 123; // or
    this.state = {          // commonly used syntax
        model : 123
    }
}

Then still according to the docs :

UNSAFE_componentWillMount() is invoked just before mounting occurs. It is called before render(), therefore calling setState() synchronously in this method will not trigger an extra rendering. Generally, we recommend using the constructor() instead for initializing state.

You are indeed using this to initialize your component's state. As pointed by others, you should instead use ComponentDidMount and use this.setState to modify the state as modifying the state directly with this.state.model is considered bad behaviour

Constructor is the only place where you should assign this.state directly. In all other methods, you need to use this.setState() instead.

Please check : https://reactjs.org/docs/react-component.html for more informations

Upvotes: 1

user11645365
user11645365

Reputation:

Because by writing onClick = {this.handleSubmit} you detach the function from the context, and in this function you have this - not your component Try to write

onClick = {this.handleSubmit.bind (this)}

or

handleSubmit = () => {console.log (this.model)}

Upvotes: 2

Dupocas
Dupocas

Reputation: 21317

Code declared in componentWillMount will not be in the instance scope for a simple reason: The component isn't mounted yet. If you want to declare a global property in your class, just use componentDidMount or declare it inside the class body like any other method.

Upvotes: 1

Related Questions