Is constructor needed for a ReactJS component class - reactjs

I'm using ReactJS in Typescript. Do I need the "Constructor" code below? It works fine without it and I looked at the trans-piled JavaScript and it appears to add it in automatically anyway.
interface myProps {
children?: any;
}
class MyButton extends React.Component<myProps, {}> {
constructor(props: myProps) { //Needed ???
super(props);
}
render() {
return (<div>
<button>
{this.props.children}
</button>
</div>);
} //end render.
} //end class.

No, you don't need to.
In fact, you could write a simple component like this as a function.
const MyButton = (props) => {
return (
<div><button>{props.children}</button></div>
);
};

As mentioned in the accepted answer:
const MyButton = (props) => {
return (
<div><button>{props.children}</button></div>
);
};
This works but it's not the same - not at all. This is constructing a StatelessComponent (without state, without lifecycle-hooks, it's just a plain function, returning only the JSX or the part of the "render" function).
If you need state or lifecycle-hooks, you must extend from React.Component - like it is already done in the question.
To actually answer your question - yes constructor is needed. That's because you are extending of an existing class which is already asking for an initial property ("props") that must be given on the construct -> because it is a react class, react will call internally something like
new MyButton(props);
He will always give you the props object into the instantiated Component. Now, by extending this existing react component class, you must achieve the same - or you will end up missing your "props" object. To make it possible, that one can still pass "props" to your newly defined component, you have to define the props also on your constructor, so you have to write this:
constructor(props: myProps) { .. }
Otherwise, you can't pass anything when you call "new MyButton(props)" -> well, this will not except or bring an error, but "props" will just be "null" in your further code of "MyButton".
Last but not least - you have to call the "super" in an extended version.
super(props);
Otherwise, you won't pass the given "prop" object to the basic class which you're extending from. Here, it could work too without it, but - then "props" will be "null" in any code of "React.Component" itself.
So, yes it is needed!
Basically you can answer this question yourself by simply using a debugger - just open your web-dev tools, jump to your component code, make a breakpoint in your constructor and watch closely what is happending and what is passed ;) Then, delete the property in the constructor once.. and remove the super call once... how will it except/break apart? ;)
Update:
The other question you can always ask yourself when creating new react components: do i need state? do i need lifecycleHooks?
If one of those is yes, you'll have to extend from React.Component - because only the basic class is giving you this sugar. But as can say, no, i don't need any of those - always go with a StatelessComponent:
const MyComp = (props) => (
<div></div>
)
And try to avoid local component states too - you can do much better with one global state trough react-redux and selectors ;)

Constructor and Super are no longer necessary in react. State can be defined without a constructor and lifecycle hooks also work fine. This is a result of Babel transpiling the components that way: http://2ality.com/2017/07/class-fields.html
In traditional ES6 this is currently not the case.

Today, the constructor is needed only when you must initialize a component with a state from props.
import React from 'react'
class AChildComponent extends React.Component {
constructor(props){
super(props)
this.state = {
myState: props.myStateFromProps
}
}
render(){
return(
<div>
<p>{this.state.myState}</p>
</div>
)
}
}
export default AChildComponent

Related

How does React's Component's constructor really work?

I appreciate it if anybody can explain why the following code works.
I created a NumberListBase React component. Then created another one, named NumberList and derived it from NumberListBase.
In the constructor of the two components I purposely don't pass 'props' argument to the parent class when calling super().
class NumberListBase extends React.Component {
constructor(props) {
super();
Log("NumberListBase.ctor: ", this.props, props);
}
}
class NumberList extends NumberListBase {
constructor(props) {
super();
Log("NumberList.ctor: ", this.props, props);
}
render() {
const numbers = this.props.numbers;
const listItems =
numbers.map((n) => <li key={`${n}`}>{n}</li>);
return (<ul>{listItems}</ul>);
}
}
const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
<NumberList numbers={numbers} />,
document.getElementById('root')
);
I expected that render() will fail, because this.props would be undefined in it.
The log messages I put in the constructors shows clearly that the 'props' argument and 'this.props' are 'undefined' in NumberListBase constructors.
But, in complete amazement, the component rendered correctly and showed the numbers, meaning that the 'props' got to React.Component somehow and React.Component could put it inside 'this.props'!
This is a codepen I created for this question.
https://codepen.io/mansoor-omrani/pen/oKaMXV
I also created a jsfiddle snippet to test how constructors work in a class hierarchy.
https://jsfiddle.net/omrani/thnj2zu4/11/
I checked React.Component source code to see how this class is defined.
https://github.com/facebook/react/blob/master/packages/react/src/ReactBaseClasses.js
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;
}
React.Component is just a simple function. I'm still wondering how, where and when 'this.props' was set!
When you call super() without the props, you’ll still be able to access this.props in the render and other methods because React assigns props on the instance right after calling your constructor.
We pass props into the super method only when we need to use props inside the constructor.
The reason why they implemented this behaviour is unclear, probably for future compatibility reasons, as Robin Pokorny replied to the below question.
ref: What's the difference between "super()" and "super(props)" in React when using es6 classes?

Assigning props to variable in React class component

I have a simple react component. I would like to assign a variable inside the component method to props. I've tried this method works with functional components:
class Pets extends React.component {
constructor(props) {
super(props)
}
const {dog, cat, frog} = props
// the code on the line above does not work
render() {
return (
<div>
{dog.name}
{cat.name}
</div>
)
}
}
That will not work. props is a property on the instance of the component you created with <Pets /> JSX for example. It needs to be inside the instance methods of the class Pets. It will work if you do it in the render method by const {dog, cat, frog} = this.props. props in the class body as you have now in the question is not what them expected to be.
Inside the constructor function just const {dog, cat, frog} = props will work, because here props object is received as an argument. so this.props (after the super(props) line)andprops` is same object.
Generally you unpack props where you need them, for example you need those inside the render to create some output, so you unpacked it there. I tried to explain in this answer what props means in the class body, and instance methods body, how you can access the props in different methods etc. But as xadm said, unpacking them inside the constructor by thinking you will access them later in other methods will not work due to the scope boundary, unless you store them as a property to the instance again using this.dog = props.dog. But this is an horrible idea, never do this. Just unpack them when you need any property from props object in that place only.

Unable to refer to immediately destructured props in class component, do I have to use `this.props` every time?

In a stateless functional component, we can use destructured props as the function arguments:
const Blah = ({ hello, world }) {
return <div>{hello} {world}</div>
}
This gives very clean code and not only is it obvious what props are being passed, we don't have to use this.props everywhere.
Having to use this.props all the time in a class component can take up a lot of room all over the component and is not nearly as nice to use:
class Blah extends Component {
render() {
return (
<div>{this.props.hello} {this.props.world}</div>
)
}
}
My questions is, what similar approach can we take for class components so that we don't have to use this.props everywhere?
One solution I can think of would be to destructure the props in the render method, but of course you would have to do that for every method in your class should you want to use the destructured name.
Nope I'm afraid there's no way to. The functional component is essentially a render() function of a class component, the "cleaniness" is kinda the same actually (:

What exactly is a "Prop" in React?

I just started using React native on iOS to see how it feels like and I have a silly question..
I see everyone talking about "Props", whenever I read an article or a tutorial, the author uses this term a lot and it's the same in the code. For instance, in class declarations I often see constructors like :
class MyClass extends Component {
constructor(props) {
super(props);
this.state = { message: '' };
}
}
I can't find a clear explanation of what a prop is, could anyone enlighten me about that ?
props are the values that you pass down to your React component. So whenever you have a component you'll see something like this:
<MyComponent value1={value1} isTrue={true} />
In addition to the answer of Keith, below you can find the non-JSX version that uses a 'color' property.
// Output (JS):
var app = React.createElement(Nav, {color:"blue"});
React Props are read-only arguments passed from one React Component to another (down the component hierarchy).
Let's say you have two components - App and List. Then, inside App we have a list with information from developers. If we wanted to pass the array to the List component, we'd do something like this (<List list={developers} />)
import React from 'react';
const App = () => {
const developers= [
{
id: 1,
name: 'Randy'
},
{
id: 2,
name: 'Tiago Peres'
},
];
return (
<div>
<h1>Developers in StackOverflow</h1>
<List list={developers} />
</div>
);
};
const List = props =>
props.list.map(item => (
<div key={item.id}>
<span>{item.name}</span>
</div>
));
export default App;
This would be the result
Using this, we don't need to have too much information in the global scope.
If you want to know more about it, there's a great article from Robin Wieruch that i would suggest you to read.
To understand the specific case you mention, one must know some basics of React and also ECMAScript 6 (ES6). Based in content from W3Schools's React Tutorial,
A class created with a class inheritance inherits all the methods from another class.
To create a class inheritance we use the extends keyword.
You're creating a class named MyClass which will inherit the methods from the Component class.
The properties of a class are assigned inside a constructor() method
The constructor function is called automatically when the object is initialized.
The super() method refers to the parent class and so executes the parent component's constructor function.
If the component has a constructor function, the props should always be passed to the constructor and also to the React.Component via the super() method.
super(props) would call the Component constructor passing in props as the argument.
While most likely you could just use super(), using super(props) ensures this.props is set even before the constructor exits.
Even though in your case the state object has only message property, you can have as many as you like.
You can use this.state.message anywhere in the component.
Props : Props is nothing but property of component and react component is nothing but a JavaScript function. Props are immutable. You can pass props between components.You can pass props from parent component to child component directly. For passing from child to parent you need use concept of lifting up states.
class Parent extends React.Component{
render()
{`enter code here`
return(
<div>
<Child name = {"Sara"}/>
</div>
);
}
}
class Child extends React.Component{
{
render(){
return(
<div>
{this.props.name}
</div>
);
}
}

Context undefined in constructor - react

export default class Printer extends React.PureComponent<PrinterProps> {
static contextType = PrinterContext;
constructor(props: PrinterProps, context: PrinterInterface){
super(props, context);
this.PrinterInfo = getPrinterInfo(this.context);
}
I need to pass context to super to be able to access it within the constructor.
Passing of context to constructor is not there in their latest documentation -
https://reactjs.org/docs/context.html
but it is there in the legacy api documentation.
https://reactjs.org/docs/legacy-context.html#referencing-context-in-lifecycle-methods
Since passing context to super will be deprecated in versions 17 and above, what is a way to be able to accees context within passing it to super in constructor ?
Thanks!
Since passing react context to super will soon be deprecated, you won't be able to use the context in constructor. Another point would be, I've seen functional component is more preferred way of creating components (this is highly discussion topic)
I would recommend using functional component and then simply use useEffect or useContext hook if it makes sense in the overall situation.
You can follow the same approach in the class component as well for eg. using react lifecycle method componentDidMount() since context will be available once component is mounted, this lifecycle method makes sense to use context and call the method getPrinterInfo() in it.
If you are not planning to update the react to 17, you can use the code that you have written since it is working, but if you want to update the react in future and want to work with it follow the other approach.
export default class Printer extends React.PureComponent<PrinterProps, State> {
static contextType = PrinterContext;
context!: React.ContextType<typeof PrinterContext>;
constructor(props: PrinterProps){
super(props);
}
componentDidMount() {
this.getPrinterInfo();
}
getPrinterInfo = () => {
// you should have access to this.context
}
}

Resources