This error occurs when trying to use class field syntax to initialize state without proper Babel configuration, or when the build tool doesn't support class properties. The state property must be assigned in the constructor using `this.state = {}` or class properties transform must be enabled.
This error indicates that your React class component is trying to initialize state using class field syntax (`state = {}`) but your build environment doesn't support this modern JavaScript feature. Class field syntax (also called class properties) is a Stage 3 JavaScript proposal that allows you to define class properties directly in the class body without a constructor. While modern build tools like Create React App and Vite include the necessary Babel transform by default, older projects or custom build configurations may not have this feature enabled. When the class properties transform is missing, JavaScript engines treat `state = {}` as invalid syntax, requiring you to initialize state the traditional way inside the constructor using `this.state = {}`. This error commonly appears when migrating legacy codebases, using outdated build tools, or working with custom Webpack/Babel configurations that haven't been updated.
First, check if you're using a modern build tool that includes class properties support by default:
Create React App (CRA):
# Check CRA version (should be 2.0+)
npm list react-scriptsVite:
# Check Vite version (has built-in support)
npm list viteIf using a custom Babel setup, check your .babelrc or babel.config.js:
{
"presets": ["@babel/preset-env", "@babel/preset-react"],
"plugins": ["@babel/plugin-proposal-class-properties"]
}If you have a custom Babel configuration and the plugin is missing, install it:
npm install --save-dev @babel/plugin-proposal-class-propertiesOr with Yarn:
yarn add -D @babel/plugin-proposal-class-propertiesThen add it to your Babel configuration:
{
"presets": ["@babel/preset-env", "@babel/preset-react"],
"plugins": ["@babel/plugin-proposal-class-properties"]
}If you can't immediately fix the build configuration, convert your component to use constructor-based initialization:
Before (class field syntax):
class MyComponent extends React.Component {
state = {
count: 0,
message: 'Hello'
};
render() {
return <div>{this.state.count}</div>;
}
}After (constructor initialization):
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0,
message: 'Hello'
};
}
render() {
return <div>{this.state.count}</div>;
}
}Remember to always call super(props) before accessing this.state or this.props in the constructor.
Modern versions of @babel/preset-env automatically include class properties support when targeting appropriate browsers. Update your preset configuration:
npm install --save-dev @babel/preset-env@latest @babel/preset-react@latestUpdate your babel.config.js:
module.exports = {
presets: [
['@babel/preset-env', {
targets: {
browsers: ['last 2 versions', 'not dead']
}
}],
'@babel/preset-react'
]
};With recent @babel/preset-env versions, class properties are included automatically based on your target browsers.
If you're using TypeScript, ensure your tsconfig.json has the correct target and settings:
{
"compilerOptions": {
"target": "ES2022",
"jsx": "react",
"useDefineForClassFields": true
}
}For TypeScript 4.3+, useDefineForClassFields should be set to true to match the ES2022 class fields specification. This ensures TypeScript compiles class fields correctly.
Class Fields vs Class Properties:
The official JavaScript specification now includes class fields (ES2022), which is slightly different from the Babel class properties transform proposal. The main difference is initialization timing - class fields are initialized before the constructor runs, while the Babel transform initializes them inside the constructor.
Migration Strategy:
When updating older React projects, you may encounter thousands of components using class field syntax. Instead of converting all components to use constructors, prioritize fixing your build configuration. Modern tooling (Create React App 2.0+, Next.js 9.3+, Vite) includes this support out of the box.
Function Components Alternative:
If you're starting a new project or refactoring, consider using function components with hooks instead of class components. This avoids the entire class initialization debate:
function MyComponent() {
const [count, setCount] = useState(0);
const [message, setMessage] = useState('Hello');
return <div>{count}</div>;
}Webpack Configuration:
If using custom Webpack setup, ensure babel-loader is properly configured:
module.exports = {
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env', '@babel/preset-react'],
plugins: ['@babel/plugin-proposal-class-properties']
}
}
}
]
}
};Debugging Tips:
To verify if class properties are working, add a simple test component and check if it compiles. If compilation succeeds but runtime fails, the issue may be in your target browser support rather than build configuration.
React Hook useCallback has a missing dependency: 'variable'. Either include it or remove the dependency array react-hooks/exhaustive-deps
React Hook useCallback has a missing dependency
Cannot use private fields in class components without TS support
Cannot use private fields in class components without TS support
Cannot destructure property 'xxx' of 'undefined'
Cannot destructure property of undefined when accessing props
useNavigate() may be used only in the context of a <Router> component.
useNavigate() may be used only in the context of a Router component
Cannot find module or its corresponding type declarations
How to fix "Cannot find module or type declarations" in Vite