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;
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
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:
Constructor
componentWillMount
Render
componentDidMount
So after the render() is executed, the componentDidMount is getting executed and there's no change after any state change.
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.
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)}
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.
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
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() {
...
Related
I am reviewing some React Js basics and I need some clarifications about the use of the constructor method within a react class based component. My normal practice is to declare a class based component and define state without using the constructor, like so:
import React, { Component } from 'react';
export class Testing extends Component {
state = {
example: "Hello World!!!"
}
render() {
return <div>
{this.state.example}
</div>;
}
}
export default Testing;
Since state is so easy to use without the (seemingly) pointless constructor, I began asking myself what the constructor was for. Just to clarify what I mean by the constructor, it is when you declare state like this instead of the above example:
constructor(props) {
super(props)
this.state = {
example: "Hello World!!!"
}
}
I found the suggestion in the react documentation that it is best practice to utilize the constructor, but it did not say why. After a little searching, I found a source that suggested that the constructor give you access to the props. I tested this and do see how the constructor gives access to props; however, the class can access props WITHOUT using the constructor, simply by stating this.props.myTest. I tested this as well by defining props in a parent component and drilling them down to the child component. I was able to access the props just fine with the this.props.myTest statement, no constructor necessary. So my question is, "What specifically does the constructor do, and when is it necessary (or is it ever necessary)?"
"when is the constructor necessary ?":
The constructor is not necessary, if you don't need it.
You might need a constructor e.g. if you need to bind a method to the class instance (so that this keeps pointing to the
class instance if you pass the function over to some other execution context):
export class Testing extends Component {
constructor( props ) {
super( props );
this.myMethod = this.myMethod.bind( this );
}
myMethod(){
console.log( this.props );
}
render() {
return <button onClick={ this.myMethod }>
click
</button>;
}
}
"What specifically does the constructor do" ?
A constructor "creates the instance" in javascript. So without a constructor, there would be no instance.
But also there is inherently always a constructor, even if you don't define one specifically.
You can define a constructor to overwrite the default constructor or to add some extra logic to be run
additionally to the super-constructor.
Accessing this.props in React
In javascript you could not access this.props without calling super(props).
Note that the constructor argument props and the instance property this.props are different "things".
Let's rename the constructor argument for now, to make it more obvious:
class SuperClass {
constructor( constructorArguments ) {
this.props = constructorArguments;
}
}
class DerivedClass extends SuperClass {
constructor( props ) {
super(); // <-- call the SuperClass constructor
}
method(){
console.log( this.props ); // <-- this.props is obviously never defined
}
}
const instance = new DerivedClass('some props');
instance.method();
But React "takes measures" to assign this.props anyway,
even when super(props) was never called.
But that happens later (after the constructor is done),
so you are able to access this.props in other methods later, but not inside the constructor:
export class Testing extends Component {
constructor( constructorArguments ) {
super(); // <-- super() is called without arguments
console.log( this.props ); // <-- this.props is undefined
}
render() {
console.log( this.props ); // <-- React sorted it out, now this.props is available
return null;
}
}
If you pass the constructor arguments to the super class constructor, then you can access this.props
inside the constructor:
constructor( constructorArguments ) {
super( constructorArguments ); // <-- super() is called with arguments
console.log( this.props ); // <-- this.props is available
}
React recommends to call super(props) anyway, to avoid introducing bugs with later changes.
I might add that it is very little extra code that doesn't do any harm.
Defining the state
class fields were not always available, so you had to define the state inside
the constructor, as the React example shows (like this.state = { value: 'value' }).
I personally think that it is probably ok now to use the class fields, but I always
tend to follow the official documentation, even if it might be outdated. There still
might be implications which I am not aware of.
See also: is-it-better-to-define-state-in-constructor-or-using-property-initializers
As many know, this.someFunction = this.someFunction.bind(this) can be used in React class components. However, sometimes it's burdensome to create classes for very simple components. So, how can I bind a function to this without creating a class?
use arrow function arrow function
In React 16.8, you can use hooks for stateful components, essentially allowing you to write everything as a function and eliminating the need to use classes and all the caveats that come with them (this, .bind() etc).
Usage example
Here's an example of using the useState() hook and the useEffect() hook inside a function, along with an arrow function, which is already bound to the component's context:
import React, { useState, useEffect } from 'react';
function LimitedTextarea({ rows, cols, value, limit }) {
const [content, setContent] = useState(value);
const setFormattedContent = text => {
text.length > limit ? setContent(text.slice(0, limit)) : setContent(text);
};
useEffect(() => {
setFormattedContent(content);
}, []);
return (
<div>
<textarea
rows={rows}
cols={cols}
onChange={event => setFormattedContent(event.target.value)}
value={content}
/>
<p>
{content.length}/{limit}
</p>
</div>
);
}
Short explanation
You use useState() to create a state variable content and a method to update that variable, setContent().
You create an arrow function setFormattedContent to update the content state variable via the setContent method, which is already bound to context.
You use useEffect() to call setFormattedContent on the value of the content state variable.
Finally, you return whatever you would have in your render() method in a class component.
this makes sense in class component because it refers to component instance. It doesn't make sense in functional component because it is either undefined or a global, depending on the environment and how a function was declared.
As for class components, explicit constructor can be omitted if it's not needed, class fields can be used to assign instance properties, including bound methods:
class Foo extends Component {
foo = this.foo.bind(this);
foo() { ... }
...
}
Which is syntactic sugar for:
class Foo extends Component {
constructor(props) {
super(props);
this.foo = this.foo.bind(this);
}
foo() { ... }
...
}
Bound prototype methods have several benefits over instance arrow methods.
Yes arrow function is the solution.
Bind with this,
this.someFunction = this.someFunction.bind(this)
Using arrow function,
someFunction = () => {
// do something
}
There is no need to bind "this" If you use arrow function. It has simple and cleaner syntax.
someFuncton = () => {
// whatever write here...
}
Suppose that I had a React component such as
import { getEventListener } from 'controls';
class SomeComponent extends React.Component {
render() {
return (<div onClick={this.handleEvent}></div>)
}
handleEvent = (event) => {
getEventListener(event, this);
}
}
And I have another file such as
export function getEventListeners(event, component) {
component.setState({x: 1};
}
If getEventListeners calls set state from the component to change one of the properties would it cause an issue?
This causes the design issue, passing the whole component by reference and accessing it in a function breaks the principle of least privilege. Calling the function with a context like getEventListener.call(this, event) would have the same problem.
If getEventListener isn't supposed to be reused between components, it shouldn't be extracted from a component where it's used. It uses this.setState method and clearly belongs to a class. In case multiple inheritance is involved, a mix-in can be used.
A solution that is idiomatic to React is reusable state updater function. It's decoupled from a component and supposed to be used for pure synchronous functions:
export const getEventListeners = event => state => {
// return state object that derives from an event
};
...
this.setState(getEventListeners(event));
I want to know the conditions where by a constructor is not needed in a component's class declaration. I figure it is for stateless components, but are there any other reasons? Would not having any functions inside the component (besides life cycle functions) be one, for example?
I think it would be appropriate to just leave here an excerpt from react docs (emphasis mine):
The constructor is the right place to initialize state. If you don't
initialize state and you don't bind methods, you don't need to
implement a constructor for your React component.
I usually only add a constructor if the component has a internal state I need to set up before it is used, otherwise I leave out the constructor. Having functions in the component doesn't affect my decision in this regard
You don't actually need a constructor at all in any case if you use the babel stage-2 preset, because it provides the class properties that effectively replace its usage:
class Component extends React.Component {
constructor() {
this.state = {};
this.handleClick = this.handleClick.bind(this);
}
handleClick() { console.log('click'); }
}
becomes
class Component extends React.Component {
state = {};
handleClick = () => console.log('click');
}
Ignoring this, a constructor is needed only if you need to bind component methods to its context, or if you need to initialize the state property.
Another case is if you need to do something with the this.props class property, but this is considered an anti-pattern by React.
class Component extends React.Component {
constructor() {
this.state = {
// don't do this! anti-pattern! duplication of source of truth!
duplicatedState: this.props.myName,
};
}
}
Which is better (more performant), if one it is:
A:
class Man extends React.Component {
constructor(props) {
super(props)
this.talk = this.talk.bind(this)
this.state = {}
}
talk() { .. }
render () {
return <div onClick={this.talk}>talk!</div>
}
}
B:
class Man extends React.Component {
constructor(props) {
super(props)
this.state = {}
}
talk() { .. }
render () {
return <div onClick={this.talk.bind(this)}>talk!</div>
}
}
C:
class Man extends React.Component {
constructor(props) {
super(props)
this.state = {}
}
talk() { .. }
render () {
return <div onClick={() => this.talk()}>talk!</div>
}
}
I think that calling the bind method directly in the render method could be negligible, but after all the render method is called ton of times. I want to understand if making a change in a big codebase is it worth it or not.
As per React DOC (last para of the page):
onClick={(e) => this.handleClick(e)} and onClick={this.talk.bind(this)}
The problem with this syntax is that a different callback is created
each time the component renders. In most cases, this is fine.
However, if this callback is passed as a prop to lower components,
those components might do an extra re-rendering. We generally
recommend binding in the constructor or using the property initializer
syntax, to avoid this sort of performance problem.
MDN DOC:
Function.prototype.bind():
The bind() method creates a new function always.
Binding method in the constructor:
However if you bind the method in the constructor:
this.handleClick = this.handleClick.bind(this);
and use it like this:
onClick={this.handleClick}
It will create only one instance and use that instance always. So binding method in the constructor means you end up binding only once and you can re-use it as many times, even if the render() method is called multiple times the same function will be used.
property initilizer syntax (this is experimental syntax.):
By this way you don't need to bind all the methods in the constructor, and it will not create multiple callbacks also.
handleClick = () => {
.....
}
The best solution will be auto binding internal methods. using arrow functions as methods.
So we don't rely on the constructor to bind the internal methods, and for example having multiple internal methods will just increase the number of lines of your files unnecessarily
Here is an implementation of what I'm saying:
class Man extends React.Component {
constructor(props) {
super(props)
this.state = {};
}
talk = () => { .. }
render () {
return <div onClick={this.talk}>talk!</div>
}
}
In order for this to work, you should use transform-class-properties from Babel Stage 2 preset
If we are to define 'more performant' as something that requires the least amount of computational resource, then option A (binding in the constructor) would be the most performant.
As you state, this is because this only happens once during the creation of an instance of the component. The .bind returns a newly bound function which is referenced later on.
The latter two options will be creating new functions (bound or anonymous) on every render, which is not necessary in this context.
I think you should do binding in constructor as calling bind returns a new function. It should be called one time for performance reasons. In you call it in render, bind will be called on every render and will return a new reference each time.