Class components in React that extend React.Component must call super(props) in their constructor before accessing this. This error occurs when a constructor is defined without calling super, preventing React from properly initializing the component instance.
When you define a class component in React by extending React.Component, you create a JavaScript class that inherits from React's Component class. In JavaScript, whenever a child class has a constructor, it must call super() before accessing the "this" keyword. This is because super() initializes the parent class (React.Component), which sets up all the necessary properties and methods that your component needs to function correctly. React uses the parent constructor to initialize essential component properties like state, props, context, and lifecycle methods. If you define a constructor without calling super(props), the parent class initialization is skipped, leaving your component in an invalid state. Any attempt to access "this" will fail because the JavaScript engine hasn't properly set up the instance yet. This is a fundamental requirement of JavaScript inheritance, not just a React-specific rule. React simply enforces it strictly because without it, components become unusable.
In any class component constructor, the first line must be a call to super(props):
// WRONG - no super call
class MyComponent extends React.Component {
constructor(props) {
this.state = { count: 0 }; // Error!
}
}
// CORRECT - super(props) called first
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
}The super(props) call must be the very first statement in your constructor, before any other code that accesses "this".
Always pass the props parameter to super():
// WRONG - super() without props
class MyComponent extends React.Component {
constructor(props) {
super(); // Missing props!
this.state = { count: 0 };
}
}
// CORRECT - props passed to super
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
}While super() without props might not cause an immediate error, passing props ensures that this.props is properly initialized and available throughout the component.
The super() call must come before any reference to "this":
// WRONG - this.props accessed before super
class MyComponent extends React.Component {
constructor(props) {
console.log(this.props); // Error!
super(props);
}
}
// CORRECT - super called first
class MyComponent extends React.Component {
constructor(props) {
super(props);
console.log(this.props); // Now safe
}
}JavaScript enforces this restriction at the language level. The super() call initializes the parent class first, which makes "this" valid for use.
Here's the recommended pattern for class component constructors:
class MyComponent extends React.Component {
constructor(props) {
// 1. Call super first
super(props);
// 2. Now you can initialize state
this.state = {
count: 0,
message: ''
};
// 3. Bind methods that use "this"
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState({ count: this.state.count + 1 });
}
render() {
return (
<button onClick={this.handleClick}>
Count: {this.state.count}
</button>
);
}
}This pattern ensures all initialization happens in the correct order: super first, then state, then method binding.
If you want to avoid binding methods in the constructor, use class property arrow functions:
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
// No need to bind arrow function methods
}
// Arrow function - automatically bound
handleClick = () => {
this.setState({ count: this.state.count + 1 });
};
render() {
return <button onClick={this.handleClick}>Count: {this.state.count}</button>;
}
}Arrow function properties are a modern JavaScript feature (class fields) that automatically preserve the "this" context. This eliminates the need to call .bind() in the constructor.
Modern React development favors function components with Hooks over class components. If you're starting new development, consider using a function component instead:
// OLD - class component
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
handleClick = () => {
this.setState({ count: this.state.count + 1 });
};
render() {
return <button onClick={this.handleClick}>Count: {this.state.count}</button>;
}
}
// NEW - function component with Hooks
function MyComponent() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>
Count: {count}
</button>
);
}Function components eliminate the need for constructors, super calls, and method binding entirely. They're simpler, more readable, and the recommended approach in React 16.8+.
Use ESLint with React plugin to catch missing super() calls automatically:
npm install --save-dev eslint eslint-plugin-reactAdd to your .eslintrc.js:
module.exports = {
parser: "@babel/eslint-parser",
plugins: ["react"],
rules: {
"react/no-this-in-sfc": "warn",
"no-this-before-super": "error"
},
parserOptions: {
ecmaVersion: 2021,
sourceType: "module",
ecmaFeatures: { jsx: true }
}
};ESLint will flag this error during development before you encounter it at runtime.
The super() requirement is part of JavaScript's class inheritance model and predates React. When you extend a class, the child class constructor must call super() before using "this". This is enforced by the JavaScript engine itselfβit will throw a ReferenceError if you try to access "this" before calling super().
For TypeScript users, the TypeScript compiler will catch this error at compile time if you have strict checks enabled. If you see "Cannot access 'this' before super()" in TypeScript, it's a compile-time error, not a runtime warning.
If you're migrating from other frameworks (Vue, Angular) where constructors aren't typically used, remember that React class components rely heavily on the constructor pattern for initialization. The super(props) call is a common point of confusion for developers new to React or class components. In practice, modern React teams increasingly move away from class components entirely, favoring function components with Hooks, which completely eliminate this requirement.
Prop spreading could cause security issues
Prop spreading could cause security issues
Error: error:0308010C:digital envelope routines::unsupported
Error: error:0308010C:digital envelope routines::unsupported
React Hook "useEffect" is called conditionally. React Hooks must be called in the exact same order in every component render.
React Hook useEffect placed inside a condition
Hook can only be called inside the body of a function component
Hook can only be called inside the body of a function component
Rollup failed to resolve import during build
How to fix "Rollup failed to resolve import" in React