useContext only works in stateless functional component

The problem is what the error says. React hooks aren't available in class components. Due to differences between class components and function components, hooks cannot be used with the former.

As the documentation says,

Hooks let you use more of React’s features without classes. Conceptually, React components have always been closer to functions. Hooks embrace functions, but without sacrificing the practical spirit of React. Hooks provide access to imperative escape hatches and don’t require you to learn complex functional or reactive programming techniques.

Hooks are supposed to address common use cases that are specific to class components which couldn't be previously implemented with stateless functional components alone. Functional components aren't stateless since React 16.8 and are allowed to have a state and trigger own updates.

As for useContext hook,

When the provider updates, this Hook will trigger a rerender with the latest context value.

It would be messed up in class component due to difference between functional and class components. Component function is called each time the component is rendered:

const Foo = props => {

  const context = useContext(Context);
  // use context
}

There's no place in class component that would behave the same way except render function. And if lifecycle-specific tasks go to render function, this means that a class was a wrong choice, and class component needs to be refactored to a function. A counterpart to useContext in class components is contextType, which is currently restricted to single context.

For multiple contexts it's still required to receive them through context Consumer inside render, or as props from higher-order component wrapper:

const contextsHOC = (contexts = {}) => Comp => (
  props => {
    const contextProps = {};
    for (const prop in contexts) {
       // eslint-disable-next-line react-hooks/exhaustive-deps
       contextProps[prop] = React.useContext(contexts[prop]);
    }
    return <Comp {...props} {...contextProps}/>;
  }
);

@contextsHOC({ bar: BarContext, baz: BazContext });
export default class FooComponent extends Component {
  // contexts are mapped to this.props.bar and this.props.baz
  ...
}

// or

class FooComponent extends Component { ... }
export default contextsHOC({ ... })(FooComponent);

Passing contexts as props allows for additional optimization with PureComponent or shouldComponentUpdate.


useContext is a hook that consumes a context and can only be used in functional components.

If you want to consume context in class components, you will need to look at alternative methods such as Consumer Component, official docs for this here


If you really want to use classes (i actually came from Angular and i still prefer use classes) you can workaround easily like that:

class ComponentImpl extends React.Component<any> {
  constructor(props?) {
    super(props);
  }

  render() {
    return (
      <div>
        CounterButton: <button onClick={() => {this.props.appContext.setCount(this.props.appContext.count + 5)}}>App Counter + 5</button>
      </div>
    )
  }
}

export function Component() {
  let appContext = useContext(AppContext);

  return <ComponentImpl appContext={appContext}></ComponentImpl>
};

And you just use it: <Component></Component>