When is it important to pass props to super(), and why?
class MyComponent extends React.Component {
constructor(props) {
super(); // or super(props) ?
}
}
There is only one reason when one needs to pass props to super():
When you want to access this.props in constructor.
Passing:
class MyComponent extends React.Component {
constructor(props) {
super(props)
console.log(this.props)
// -> { icon: 'home', … }
}
}
Not passing:
class MyComponent extends React.Component {
constructor(props) {
super()
console.log(this.props)
// -> undefined
// Props parameter is still available
console.log(props)
// -> { icon: 'home', … }
}
render() {
// No difference outside constructor
console.log(this.props)
// -> { icon: 'home', … }
}
}
Note that passing or not passing props to super has no effect on later uses of this.props outside constructor. That is render, shouldComponentUpdate, or event handlers always have access to it.
This is explicitly said in one Sophie Alpert's answer to a similar question.
The documentation—State and Lifecycle, Adding Local State to a Class, point 2—recommends:
Class components should always call the base constructor with props.
However, no reason is provided. We can speculate it is either because of subclassing or for future compatibility.
(Thanks #MattBrowne for the link)
In this example, you are extending the React.Component class, and per the ES2015 spec, a child class constructor cannot make use of this until super() has been called; also, ES2015 class constructors have to call super() if they are subclasses.
class MyComponent extends React.Component {
constructor() {
console.log(this); // Reference Error
}
render() {
return <div>Hello {this.props.name}</div>;
}
}
By contrast:
class MyComponent extends React.Component {
constructor() {
super();
console.log(this); // this logged to console
}
render() {
return <div>Hello {this.props.name}</div>;
}
}
More detail as per this excellent stack overflow answer
You may see examples of components created by extending the React.Component class that do not call super() but you'll notice these don't have a constructor, hence why it is not necessary.
class MyOtherComponent extends React.Component {
render() {
return <div>Hi {this.props.name}</div>;
}
}
One point of confusion I've seen from some developers I've spoken to is that the components that have no constructor and therefore do not call super() anywhere, still have this.props available in the render() method. Remember that this rule and this need to create a this binding for the constructor only applies to the constructor.
When you pass props to super, the props get assigned to this. Take a look at the following scenario:
constructor(props) {
super();
console.log(this.props) //undefined
}
How ever when you do :
constructor(props) {
super(props);
console.log(this.props) //props will get logged.
}
When implementing the constructor() function inside a React component, super() is a requirement. Keep in mind that your MyComponent component is extending or borrowing functionality from the React.Component base class.
This base class has a constructor() function of its own that has some code inside of it, to setup our React component for us.
When we define a constructor() function inside our MyComponent class, we are essentially, overriding or replacing the constructor() function that is inside the React.Component class, but we still need to ensure that all the setup code inside of this constructor() function still gets called.
So to ensure that the React.Component’s constructor() function gets called, we call super(props). super(props) is a reference to the parents constructor() function, that’s all it is.
We have to add super(props) every single time we define a constructor() function inside a class-based component.
If we don’t we will see an error saying that we have to call super(props).
The entire reason for defining this constructor() funciton is to initialize our state object.
So in order to initialize our state object, underneath the super call I am going to write:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
// React says we have to define render()
render() {
return <div>Hello world</div>;
}
};
So we have defined our constructor() method, initialized our state object by creating a JavaScript object, assigning a property or key/value pair to it, assigning the result of that to this.state. Now of course this is just an example here so I have not really assigned a key/value pair to the state object, its just an empty object.
Dan Abramov wrote an article on this topic:
Why Do We Write super(props)?
And the gist of it is that it's helpful to have a habit of passing it to avoid this scenario, that honestly, I don't see it unlikely to happen:
// Inside React
class Component {
constructor(props) {
this.props = props;
// ...
}
}
// Inside your code
class Button extends React.Component {
constructor(props) {
super(); // 😬 We forgot to pass props
console.log(props); // ✅ {}
console.log(this.props); // 😬 undefined
}
// ...
}
As per source code
function ReactComponent(props, context) {
this.props = props;
this.context = context;
}
you must pass props every time you have props and you don't put them into this.props manually.
super() is used to call the parent constructor.
super(props) would pass props to the parent constructor.
From your example, super(props) would call the React.Component constructor passing in props as the argument.
More information on super:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/super
For react version 16.6.3, we use super(props) to initialize state element name : this.props.name
constructor(props){
super(props);
}
state = {
name:this.props.name
//otherwise not defined
};
Here we won't get this in the constructor so it will return undefined, but we will be able to fetch this outside the constructor function
class MyComponent extends React.Component {
constructor() {
console.log(this); // Reference Error i.e return undefined
}
render() {
return <div>Hello {this.props.name}</div>;
}
}
If we are using super(), then we can fetch the "this" variable inside the constructor as well
class MyComponent extends React.Component {
constructor() {
super();
console.log(this); // this logged to console
}
render() {
return <div>Hello {this.props.name}</div>;
}
}
So when we are using super(); we will be able to fetch this but this.props will be undefined in the constructor. But other than constructor, this.props will not return undefined.
If we use super(props), then we can use this.props value inside the constructor as well
Sophie Alpert's Answer
If you want to use this.props in the constructor, you need to pass
props to super. Otherwise, it doesn’t matter because React sets .props
on the instance from the outside immediately after calling the
constructor.
Here is the fiddle I've made:jsfiddle.net. It shows that props are assigned not in the constructor by default. As I understand they are assinged in the method React.createElement. Hence super(props) should be called only when the superclass's constructor manually assings props to this.props. If you just extend the React.Component calling super(props) will do nothing with props. Maybe It will be changed in the next versions of React.
Related
What is the correct way to access props in the constructor ? Yes i know that in the React documentation is said that
When implementing the constructor for a React.Component subclass, you
should call super(props) before any other statement. Otherwise,
this.props will be undefined in the constructor, which can lead to bugs
To be more clear , why do wee need this.props if we can just use props inside constructor
class MyComponent extends React.Component {
constructor(props) {
super(props)
console.log(props)
// -> { something: 'something', … }
// absolutely same
console.log(this.props)
// -> { something: 'something', … }
}
}
Are there some cases when to use props over this.props ?
this.props and props are interchangeable in constructor because this.props === props, as long as props is passed to super. The use of this.props allows to detect a mistake instantly:
constructor() {
super();
this.state = { foo: this.props.foo }; // this.props is undefined
}
Consistent use of this.props makes it easier to refactor constructor body:
constructor(props) {
super(props);
this.state = { foo: this.props.foo };
}
to
state = { foo: this.props.foo };
Only this. needs to be removed.
There are also typing problems with props in TypeScript, this makes this.props preferable for typed component.
This recommendation exists to prevent you from introducing errors by calling other methods on the object from the constructor, which depend on this.props. You don't want to pass props to these explicitly.
E.g. the following would be a bug, because you call doStuff before super
class MyComponent extends React.Component {
constructor(props) {
this.doStuff()
super(props)
}
doStuff() {
console.log("something is: " + this.props.something)
}
}
The correct way is - don`t use props in your constructor - just send into a parent.
But both way is working.
So, there is one special case for reading props in a constructor and it is set default state from props.
In a constructor after call super(props) are this.props and props equals. this.props = props.
Its only about what you prefer, I prefer call always this.props.
Example:
constructor(props) {
super(props)
this.state = {
isRed: this.props.color === 'red',
}
}
Be sure, that you are calling super(props) on the first line in your constructor.
I've seen many code snippets such as HelloWorld, where props is passed to super().
What is the reason to do that when this.props is not accessed in the constructor?
class HelloWorld extends Component {
constructor(props) {
super(props);
this.state = { message: 'Hi' };
this.logMessage = this.logMessage.bind(this);
}
logMessage() {
console.log(this.state.message);
}
render() {
return (
<input type="button" value="Log" onClick={this.logMessage} />
);
}
}
The constructor for a React component is called before it is mounted. When implementing the constructor for a React component subclass, you should call super(props) before any other statement.
Otherwise, this.props will be undefined in the constructor, which can lead to bugs.
Read Here for more details.
If you're not going to use this.props in your constructor, you don't have to put it into super() like this:
constructor(){
super();
this.state = { randomState: "" };
this.randomProperty = null;
}
But, in some cases, props passed from the parent component can be accessed and used inside constructor for initializing state (these props are not affected by prop change). By passing props to super, you can now use this.props inside constructor.
constructor(props){
super(props);
this.state = { randomVar: props.initialValue, propDependentState: this.props.someValue };
this.someVar = props.defaultValue;
this.anotherVar = this.props.openToChangesProp;
}
Take note that those props that are directly passed to this component are the only props accessible to the constructor. props that are mapped from state using redux connect is included in the props that can't be accessed here since the component hasn't mounted yet.
You don't have to do super(props). That is done only to access props inside the constructor. You can write:
constructor(){
super()
this.state={}
}
If you do not pass super(props):
constructor(props){
super()
console.log('this.props', this.props); // => undefined
console.log('props', props); // => whatever the props is
}
Refer this stackoverflow answer
I have BaseComponent, from which all another components inherit. But if child component has componentDidMount(), parent's componentDidMount() is not called. Is there any way to call componentDidMount() of parent's component always after componentDidMount() of child component? Here is example.
You can use the "super()" function to call the parents implementation.
componentDidMount() {
console.log('Child mounted.');
super();
}
But this is regarded as an anti-pattern. The suggested approach would be composition (details here). Unfortunately, without know what you are trying to accomplish through inheritance, we can't tell you an alternative through composition. In using your example, it can be done something like this
class Animal extends React.Component {
constructor(props) {
super(props);
}
componentDidMount() {
console.log('Parent mounted.'); // Not working.
}
render() {
return (<div>{this.props.animalType}</div>);
}
}
class Dog extends React.Component {
componentDidMount() {
console.log('Child mounted.');
}
render() {
return (<Animal animalType="Dog" />);
}
}
React.render(<Dog />, document.body);
In your example, your parent component Animal is not actually the parent but is an independent component since anyways you are rendering the Dog component.
This is the Reason that the componentDidMount of Animal Component is not getting called, in fact the Animal component itself is not being rendered but just defined.
In order for Dog to be a child of Animal component, render it from the Parent component(Animal) and change the code like
class Animal extends React.Component {
constructor(props) {
super(props);
}
componentDidMount() {
console.log('Parent mounted.'); // Not working.
}
render() {
return (
<Dog/>
)
}
}
class Dog extends Animal {
componentDidMount() {
console.log('Child mounted.');
}
render() {
return <div>Dog.</div>;
}
}
React.render(<Animal />, document.body);
JSFIDDLE
I'm new to using ES6 classes with React, previously I've been binding my methods to the current object (show in first example), but does ES6 allow me to permanently bind a class function to a class instance with arrows? (Useful when passing as a callback function.) I get errors when I try to use them as you can with CoffeeScript:
class SomeClass extends React.Component {
// Instead of this
constructor(){
this.handleInputChange = this.handleInputChange.bind(this)
}
// Can I somehow do this? Am i just getting the syntax wrong?
handleInputChange (val) => {
console.log('selectionMade: ', val);
}
So that if I were to pass SomeClass.handleInputChange to, for instance setTimeout, it would be scoped to the class instance, and not the window object.
Your syntax is slightly off, just missing an equals sign after the property name.
class SomeClass extends React.Component {
handleInputChange = (val) => {
console.log('selectionMade: ', val);
}
}
This is an experimental feature. You will need to enable experimental features in Babel to get this to compile. Here is a demo with experimental enabled.
To use experimental features in babel you can install the relevant plugin from here. For this specific feature, you need the transform-class-properties plugin:
{
"plugins": [
"transform-class-properties"
]
}
You can read more about the proposal for Class Fields and Static Properties here
No, if you want to create bound, instance-specific methods you will have to do that in the constructor. However, you can use arrow functions for that, instead of using .bind on a prototype method:
class SomeClass extends React.Component {
constructor() {
super();
this.handleInputChange = (val) => {
console.log('selectionMade: ', val, this);
};
…
}
}
There is an proposal which might allow you to omit the constructor() and directly put the assignment in the class scope with the same functionality, but I wouldn't recommend to use that as it's highly experimental.
Alternatively, you can always use .bind, which allows you to declare the method on the prototype and then bind it to the instance in the constructor. This approach has greater flexibility as it allows modifying the method from the outside of your class.
class SomeClass extends React.Component {
constructor() {
super();
this.handleInputChange = this.handleInputChange.bind(this);
…
}
handleInputChange(val) {
console.log('selectionMade: ', val, this);
}
}
You are using arrow function and also binding it in constructor. So you no need to do binding when you use arrow functions
class SomeClass extends React.Component {
handleInputChange = (val) => {
console.log('selectionMade: ', val);
}
}
OR you need to bind a function only in constructor when you use normal function like below
class SomeClass extends React.Component {
constructor(props){
super(props);
this.handleInputChange = this.handleInputChange.bind(this);
}
handleInputChange(val){
console.log('selectionMade: ', val);
}
}
Also binding a function directly in render is not recommended. It should always be in constructor
I know this question has been sufficiently answered, but I just have a small contribution to make (for those who don't want to use the experimental feature). Because of the problem of having to bind multiple function binds in the constructor and making it look messy, I came up with a utility method that once bound and called in the constructor, does all the necessary method bindings for you automatically.
Assume I have this class with the constructor:
//src/components/PetEditor.jsx
import React from 'react';
class PetEditor extends React.Component {
constructor(props){
super(props);
this.state = props.currentPet || {tags:[], photoUrls: []};
this.tagInput = null;
this.htmlNode = null;
this.removeTag = this.removeTag.bind(this);
this.handleChange = this.handleChange.bind(this);
this.modifyState = this.modifyState.bind(this);
this.handleKeyUp = this.handleKeyUp.bind(this);
this.addTag = this.addTag.bind(this);
this.removeTag = this.removeTag.bind(this);
this.savePet = this.savePet.bind(this);
this.addPhotoInput = this.addPhotoInput.bind(this);
this.handleSelect = this.handleSelect.bind(this);
}
// ... actual method declarations omitted
}
It looks messy, doesn't it?
Now I created this utility method
//src/utils/index.js
/**
* NB: to use this method, you need to bind it to the object instance calling it
*/
export function bindMethodsToSelf(objClass, otherMethodsToIgnore=[]){
const self = this;
Object.getOwnPropertyNames(objClass.prototype)
.forEach(method => {
//skip constructor, render and any overrides of lifecycle methods
if(method.startsWith('component')
|| method==='constructor'
|| method==='render') return;
//any other methods you don't want bound to self
if(otherMethodsToIgnore.indexOf(method)>-1) return;
//bind all other methods to class instance
self[method] = self[method].bind(self);
});
}
All I now need to do is import that utility, and add a call to my constructor, and I don't need to bind each new method in the constructor anymore.
New constructor now looks clean, like this:
//src/components/PetEditor.jsx
import React from 'react';
import { bindMethodsToSelf } from '../utils';
class PetEditor extends React.Component {
constructor(props){
super(props);
this.state = props.currentPet || {tags:[], photoUrls: []};
this.tagInput = null;
this.htmlNode = null;
bindMethodsToSelf.bind(this)(PetEditor);
}
// ...
}
I'm running into an issue where this is returning null in my store for my React component. I believe I need to bind this, but I am unsure. I'm also using React Router and have my component set up in a wrapper so I'm able to pass props to it. Any help is appreciated!
COMPONENT
import React from 'react';
import PaymentStore from './../store/paymentStore';
class InitialPaymentScreen extends React.Component {
constructor(props) {
super(props)
}
render() {
console.log(this.props)
return (
<div className="payment-form-submit" onClick={this.props.store.init}>Next</div>
);
}
}
class PaymentForm extends React.Component {
constructor(props) {
super(props)
}
render() {
return (
<section className="main-content payment-form-wrapper">
<InitialPaymentScreen store={this.props.store}/>
</section>
);
}
}
export default class PaymentFormWrapper extends React.Component {
render() {
return (
<PaymentForm store={PaymentStore} mode="foo"/>
);
}
}
STORE
let PaymentStore = {
handleClickNext() {
console.log("hello")
},
init() {
console.log(this) // returns null
this.handleClickNext(); // cannot read property of null
},
};
export default PaymentStore;
Looks like you need to bind it indeed. You can do that by changing
<div className="payment-form-submit" onClick={this.props.store.init}>Next</div>
to
<div className="payment-form-submit" onClick={this.props.store.init.bind(this.props.store)}>Next</div>
# or
var init = this.props.store.init.bind(this.props.store);
<div className="payment-form-submit" onClick={init}>Next</div>
Alternatively, if InitialPaymentScreen only needs init from store, the binding could happen in PaymentForm, and InitialPaymentScreen could only receive the function.
The binding needs to be done because javascript is, well, unique in some ways.
Generally, a function's this is bound to literally what's it being called from. In your case, store.init() means the init function has this as store.
Now, if you assign store.init to a variable and call that, it doesn't know what's this! (this is probably the most common issue for people learning JS) — because during invocations, it tries to infer this by seeing which object that function is stored in.
To get make the function know what's its context then, you have two options basically:
a. fn.bind(something), which returns a bound function, or
b. create an anonymous function which invokes that one