This error occurs in React class components when attempting to access this.state before it has been properly initialized as an object. It typically happens when the constructor is missing, super(props) is not called, or state is set to null/undefined instead of an object.
This error indicates that React is trying to access the state property of a class component, but finds that this.state is not an object as expected. In React class components, this.state must always be an object (or null in specific scenarios). The error occurs when the JavaScript runtime attempts to read properties from this.state but discovers it's undefined, null, or some other non-object type. This typically happens during the component lifecycle, especially in the constructor, render method, or event handlers. React expects this.state to be properly initialized before any component methods try to read or update it. When the initialization chain is broken—usually by forgetting super(props) or not setting an initial state—the error surfaces immediately.
If your class component is missing a constructor, add one and ensure you call super(props) first:
class MyComponent extends React.Component {
constructor(props) {
super(props); // This MUST come first
this.state = {
count: 0,
data: null
};
}
render() {
return <div>{this.state.count}</div>;
}
}The super(props) call is essential because it invokes the parent React.Component constructor, which sets up this and makes this.props available.
Ensure this.state is always initialized as an object (even if empty):
// ✅ Good - state is an object
constructor(props) {
super(props);
this.state = {
items: []
};
}
// ❌ Bad - state is null
constructor(props) {
super(props);
this.state = null;
}
// ❌ Bad - state not initialized at all
constructor(props) {
super(props);
// Missing this.state = {}
}If you don't need any initial state, you can use an empty object: this.state = {}
If the error occurs in event handlers, ensure proper this binding using arrow functions or bind():
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = { value: '' };
// Option 1: Bind in constructor
this.handleClick = this.handleClick.bind(this);
}
// Option 2: Arrow function (preferred)
handleChange = (e) => {
this.setState({ value: e.target.value });
}
// Traditional method needs binding
handleClick() {
console.log(this.state.value); // this will be undefined without binding
}
render() {
return (
<>
<input onChange={this.handleChange} value={this.state.value} />
<button onClick={this.handleClick}>Click</button>
</>
);
}
}Arrow functions automatically bind this to the component instance.
Ensure you're not accessing this.state before super(props):
// ❌ Bad - accessing this before super()
class MyComponent extends React.Component {
constructor(props) {
console.log(this.state); // Error! super() not called yet
super(props);
this.state = { count: 0 };
}
}
// ✅ Good - super() called first
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
console.log(this.state); // Now safe to access
}
}If you're starting a new component, consider using functional components with hooks instead:
// Modern approach - functional component with hooks
import { useState } from 'react';
function MyComponent() {
const [count, setCount] = useState(0);
const [data, setData] = useState(null);
return (
<div>
<p>{count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}Functional components avoid the this.state initialization issues entirely and are the recommended approach for modern React development.
Class Component Lifecycle: The React.Component base class sets up the component's internal state management. Without calling super(props), the base class constructor never runs, leaving this.state undefined. This is why super(props) must be the first statement in any constructor.
State as null: While React technically allows this.state to be null, it's an anti-pattern that can lead to errors. If you intentionally need a null state scenario, you should still initialize this.state as an object and store null values as properties: this.state = { data: null }.
Babel and class properties: If you're using modern JavaScript with Babel, you can use class property syntax to initialize state without a constructor:
class MyComponent extends React.Component {
state = { count: 0 }; // No constructor needed
render() {
return <div>{this.state.count}</div>;
}
}This syntax is transpiled to include the proper constructor and super() call automatically.
TypeScript considerations: In TypeScript, you can define state types explicitly, which helps catch these initialization errors at compile time:
interface MyState {
count: number;
data: string | null;
}
class MyComponent extends React.Component<{}, MyState> {
constructor(props: {}) {
super(props);
this.state = {
count: 0,
data: null
};
}
}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