react/prefer-function-component

Require function components instead of class components

Hooks only work in function components, so a class component can't share logic with the rest of a codebase that uses hooks. This rule reports every class that extends Component or PureComponent, and every other class with a method that contains JSX.

An error boundary is allowed by default, because React has no way to write one as a function.

Configure#

Off by default. To turn it on:

bunfig.toml
[lint.rules]
"react/prefer-function-component" = "error" # or "warn"

Every option, set to its default:

bunfig.toml
[lint.rules]
"react/prefer-function-component" = ["error", {
  allowErrorBoundary = true,
  allowJsxUtilityClass = false,
}]

Examples#

example.jsx1 problem
class Counter extends React.Component {
  state = { count: 0 };
  render() {
    return <button onClick={() => this.setState({ count: this.state.count + 1 })}>{this.state.count}</button>;
  }
}
example.jsxNo problems
function Counter() {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(count + 1)}>{count}</button>;
}

class ErrorBoundary extends React.Component {
  state = { failed: false };
  static getDerivedStateFromError() {
    return { failed: true };
  }
  render() {
    return this.state.failed ? <p>Something went wrong</p> : this.props.children;
  }
}

Options#

OptionDefaultWhat it does
allowErrorBoundarytrueAllow a class with componentDidCatch or static getDerivedStateFromError.
allowJsxUtilityClassfalseAllow a class that has JSX in its methods but doesn't extend Component or PureComponent.

Reported with allowErrorBoundary: false:

example.jsxwith { "allowErrorBoundary": false }1 problem
class ErrorBoundary extends React.Component {
  componentDidCatch(error) {
    report(error);
  }
  render() {
    return this.props.children;
  }
}

This class is reported by default:

example.jsx1 problem
class Columns {
  renderName(user) {
    return <b>{user.name}</b>;
  }
}

Not reported with allowJsxUtilityClass: true:

example.jsxwith { "allowJsxUtilityClass": true }No problems
class Columns {
  renderName(user) {
    return <b>{user.name}</b>;
  }
}