In React's source code, the prototype function has a signature with three parameters:
function Component(props, context, updater) {
But everytime I see somebody extends React.Component using modern ES6 features, they declare constructor with only props as follows:
constructor(props)
What is the difference between a prototype function and constructor literal? And where do the rest two arguments go?
You can obviously use all of the three params provided in the Component. But in general, only in an advanced case we use props, not every time. Similarly, you can use others.
Here's an example with context api:
ES6 class component
class ContextConsumer extends React.Component {
/*
contexTypes is a required static property to declare
what you want from the context
*/
static contextTypes = {
currentUser: React.PropTypes.object
};
render() {
const {currentUser} = this.context;
return <div>{currentUser.name}</div>;
}
}
ES6 class component with an overwritten constructor
class ContextConsumer extends React.Component {
static contextTypes = {
currentUser: React.PropTypes.object
};
constructor(props, context) {
super(props, context);
...
}
render() {
const {currentUser} = this.context;
return <div>{currentUser.name}</div>;
}
}
Example taken from this blog. I will suggest you to look into the blog to be more familiar with it.
Another param is updater which you may have used this.forceUpdate() and doing so invoke the updater. But the fact, we do not use updater directly in normal case. Though, I have not faced such case to use the updater inside the constructor. You might be able to figure out if you face some advanced case.
To be more frank and to use react with clever, I never even try to use props as far as possible. They are just provided for us so that we can utilize in lifecycle hooks when needed.
Okay, let me explain it a little bit with react code:
function Component(props, context, updater) {
this.props = props;
this.context = context;
// If a component has string refs, we will assign a different object later.
this.refs = emptyObject;
// We initialize the default updater but the real one gets injected by the
// renderer.
this.updater = updater || ReactNoopUpdateQueue;
}
Component.prototype.forceUpdate = function(callback) {
this.updater.enqueueForceUpdate(this, callback, 'forceUpdate');
};
The Component function has 3 arguments which is being utilized inside the function. Later, its prototype forceUpdate is defined on which the updater is being hooked to enqueue the forceUpdate with enqueueForceUpdate. So, this.forceUpdate actually calling the Component updater and allows us to re-render the component. I hope, looking at its prototype method makes sense now.
What is the difference between a prototype function and constructor literal?
As far as I understand, you wanted to know why constructor is being called with the desired params.
The class/function constructor is used so that you can use an override to the function. For eg, passing props inside the constructor, you wanted to do an override with this. So, you explicitly notify the function to use the props as used inside the constructor.
So Es6 added the class keyword along with the constructor for it. It is however just syntactic sugar and is still based on the prototype model as before.
I don't know about the other two argos but I would guess it has to do with the function creating its own lexical scope.
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
I found in an open source project a class like this
class ComponentName extends React.Component{
state = {
somestate here
};
render() {
return <RenderedComponent value={somethings}>{some other things}</RenderedComponent>;
}
}
is it correct to define state in this way? Shouldn't it be defined inside the class's constructor?
You don't always have to define a constructor for every class. So if you don't need to define a constructor it is fine to use the state this way.
Yes, it is perfectly correct, check this link: https://github.com/the-road-to-learn-react/react-alternative-class-component-syntax
You can do it both ways, in the constructor or using class field declarations.
yeah you can define like this it's experimental state that works similar to constructor state.
The only thing is you need to define arrow function instead of binding(if using experimental state).
If you define constructor then you can bind function there
experimental state
state = {
name: 'hello'
}
state defined in constructor where you can bind function
constructor(props) {
super(props);
this.state = {
name: ': hey'
}
this.handleChange = this.handleChange.bind(this);
}
It is a new syntax of ES6. It is 100% equal define state without constructor and define state inside constructor. So feel free to write this way. To learn more about it check their documentation.
I understand the concept of constructors in OOP languages like C++. However, I am not entirely sure when to use a constructor in REACT. I do understand that JavaScript is object oriented, but I am not sure what the constructor is actually 'constructing'.
When rendering a child component, do you need a constructor in the child component? For example:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
items: [],
error: null
}
}
render () {
return (
<React.Fragment>
<ChildComponent data={this.state.items}></ChildComponent>
</React.Fragment>
)
}
}
I will keep the example short for the sake of brevity. But, why would do you need a constructor? And would you need a constructor in the child component for props?
It is possible that my ES6 knowledge is not up to snuff.
If you don’t initialize state and you don’t bind methods, you don’t need to implement a constructor for your React component.
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.
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.
https://reactjs.org/docs/react-component.html#constructor
A constructor function is NOT required at all.
State initialization can be done directly in the body of a class and function can be assigned to properties as described below, Technically these are known as class properties, it may land up soon in native javascript, yet because almost all of us use Babel transpiler for React projects, we can use that syntax
class Comp extends React.Component {
/*
* generally we do not need to put the props in state, but even if we need to.
* then it is accessible in this.props as shown below
**/
state={ first: 1, second: this.props.second }
handler= (token) => {
this.setState(prevState => ({first: prevState.first+1}));
}
render() {
return <div onClick={this.handler}>{this.state.first} and {this.state.second } </div>
}
}
Read more details about class properties and removing constructor from react class component over here.
https://hackernoon.com/the-constructor-is-dead-long-live-the-constructor-c10871bea599
Linke in your example, it's useful use constructor when you need to initialize your state, or bind some event-listener-function
<element onClick={this.handler} />
this.handler = this.bind.handler(this); inside the constructor
I know that this question was asked many times, but it is still doesn't clear.
Many people just said:
Pass props to constructor if you want to access this.props there
one more example of the answer
Oficial doc says Class components should always call the base constructor with props. , but if we do not pass props to constructor, we will still have this.props everywhere exept constructor.
Also from react source code we can see source code of the React.Component
function ReactComponent(props, context) {
this.props = props;
this.context = context;
}
But it is confuses me even more.
super() should be called with two parametrs: props and context . But we invoked our super empty and still have access two this.props.
According to ECMA documentation super() invokes parent constructor() with parametrs passed to super() . But our super() is empty.
So my questions are:
Why official docs says:
Class components should always call the base constructor with props.
How React set props to child component if super() and constructor() is empty?
Is it bug of feature of the React that props are accessible in child component without passing props to super() and constructor()?
Here is an answer from Dan Abramov:
But if we do not pass props to constructor, we will still have
this.props everywhere except constructor.
Yes, React sets this.props anyway after the constructor runs. Still, it is confusing to have this.props work in some places and not others. Especially if both constructor and other methods call some shared method that reads this.props. So, to avoid any potential confusion, we recommend always calling super(props).
Also from source code of Create Element you can see that createElement
adds props regardless if you use super(props)
createElement() has no relation to this question. It creates an element, not an instance.
So, to get back to your question, technically it's only necessary if you plan to access this.props in the constructor or any method you call from constructor. However it's pretty confusing to have to remember this. You might know about it and not call super(props), but the next person on your team will want to access this.props in a constructor and will be surprised it doesn't work. It's just easier to always specify it to avoid these problems.
If no constructor is defined in the code for a react component you can assume it will be automatically bound behind the scenes, such as:
constructor(props){
super(props);
}
Once you have explicitly defined a constructor you must remember to always put that code in otherwise it will be left out... you are basically just overriding a default method :)
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,
};
}
}