Skip to main content
interlace
Plugin: react-featuresRules

react-class-to-hooks

react-class-to-hooks rule

Suggest migrating React class components to hooks with detailed migration path. This rule is part of eslint-plugin-react-features and provides LLM-optimized error messages with fix suggestions.

💡 Provides suggestions | 🔧 Automatically fixable

Quick Summary

AspectDetails
SeverityWarning (migration guidance)
Auto-Fix✅ Yes (suggests hooks migration)
CategoryReact / Migration
ESLint MCP✅ Optimized for ESLint MCP integration
Best ForReact projects migrating from class to functional components

Rule Details

Identifies React class components that can be migrated to functional components with hooks, providing complexity analysis and migration guidance.

A React class component is a class that extends React's Component or PureComponent, however the file names it (Component, a renamed import, React.Component, a namespace import), declared, written as a class expression, or as an anonymous export default class. A class extending a Component the file declares itself or imports from another library is not one.

An error boundary (a class with componentDidCatch or a static getDerivedStateFromError) is never reported: React has no hooks equivalent, and documents that an error boundary cannot be written as a function component.

Configuration

OptionTypeDefaultDescription
ignorePureRenderComponentsbooleanfalseSkip classes that extend PureComponent
allowComplexLifecyclebooleanfalseSkip classes using getDerivedStateFromProps or getSnapshotBeforeUpdate (no simple hook mapping)

Examples

❌ Class Component

class UserProfile extends React.Component<Props, State> {
  state = {
    loading: false,
    data: null
  };
  
  componentDidMount() {
    this.fetchData();
  }
  
  fetchData = async () => {
    this.setState({ loading: true });
    const data = await api.getUser(this.props.userId);
    this.setState({ data, loading: false });
  };
  
  render() {
    const { loading, data } = this.state;
    return loading ? <Spinner /> : <div>{data?.name}</div>;
  }
}

✅ Functional Component with Hooks

function UserProfile({ userId }: Props) {
  const [loading, setLoading] = useState(false);
  const [data, setData] = useState<User | null>(null);
  
  useEffect(() => {
    async function fetchData() {
      setLoading(true);
      const userData = await api.getUser(userId);
      setData(userData);
      setLoading(false);
    }
    fetchData();
  }, [userId]);
  
  return loading ? <Spinner /> : <div>{data?.name}</div>;
}

Configuration Examples

{
  rules: {
    'react-features/react-class-to-hooks': ['warn', {
      ignorePureRenderComponents: false,
      allowComplexLifecycle: false
    }]
  }
}

Lifecycle Method Mapping

Class LifecycleHook Equivalent
componentDidMountuseEffect(() => {}, [])
componentDidUpdateuseEffect(() => {}, [deps])
componentWillUnmountuseEffect(() => () => {}, [])
shouldComponentUpdateReact.memo()
getDerivedStateFromPropsuseState + useEffect

Comparison with Alternatives

Featurereact-class-to-hookseslint-plugin-react-hookscodemods
Class Detection✅ Yes❌ No✅ Yes
Migration Suggestions✅ Yes❌ No⚠️ Automated only
Auto-Fix✅ Yes❌ No✅ Yes
LLM-Optimized✅ Yes❌ No❌ No
ESLint MCP✅ Optimized❌ No❌ No
Complexity Analysis✅ Yes❌ No❌ No

Further Reading

Known False Negatives

  • createReactClass({...}) components are not covered; only classes.
  • A superclass the file reaches through a helper (class A extends withRouter(Component)) is not followed.

Use this rule

npm install -D oxlint-plugin-react-features
.oxlintrc.json
{  "jsPlugins": ["oxlint-plugin-react-features"],  "rules": {    "react-features/react-class-to-hooks": "error"  }}
vite.config.ts
import { defineConfig } from 'vite-plus';export default defineConfig({  lint: {    jsPlugins: ['oxlint-plugin-react-features'],    rules: {      'react-features/react-class-to-hooks': 'error',    },  },});

oxlint-plugin-react-features re-exports eslint-plugin-react-features/oxlint: the same rules under the same IDs, and no ESLint install. Why oxlint.

Did this rule catch something? Star the repo to get new CWE coverage as we ship it — or follow the AI-code-security benchmarks behind these rules.