Blending React Hooks with Class Components: Practical Patterns and Code

This article explains why mixing React Hooks with existing Class Components is often necessary, compares three integration techniques—Render Props, Higher‑Order Components, and Ref forwarding with useImperativeHandle—provides complete code examples for each, and discusses current Hook limitations and future support.

政采云技术
政采云技术
政采云技术
Blending React Hooks with Class Components: Practical Patterns and Code

Background

React added Hooks in version 16.8.0, enabling state, context, and other features in function components. Hooks are optional and do not break existing Class Component code, but many projects need to mix the two during migration.

Problem Statement

Complex lifecycle methods in Class Components (e.g., componentDidMount) often lead to large, deeply nested components, making state reuse difficult. A gradual adoption strategy requires a reliable way for Hooks and Class Components to communicate.

Integration Patterns

The following three patterns illustrate how a simple ShowHook component that toggles visibility can be built using Hooks while keeping the parent component a Class Component.

1. Render Props

Render Props passes a function via children so the child can expose internal state and handlers to the parent.

/* Child: SayHello.js */
import React, { useState } from 'react';

function SayHello({ children }) {
  const [visible, setVisible] = useState(false);
  const jsx = visible && (
    <h1 onClick={() => setVisible(false)}>Hello Hook!</h1>
  );
  return children({ changeVisible: setVisible, jsx });
}
export default SayHello;

/* Parent: ShowHook.js */
import React, { Component, Fragment } from 'react';
import SayHello from './SayHello';

export default class ShowHook extends Component {
  render() {
    return (
      <SayHello>
        {({ changeVisible, jsx }) => (
          <Fragment>
            <button onClick={() => changeVisible(true)}>showChild</button>
            {jsx}
          </Fragment>
        )}
      </SayHello>
    );
  }
}

This pattern extracts the visibility logic into a reusable function, allowing any Class Component to control the Hook‑based child.

2. Higher‑Order Component (HOC)

An HOC wraps a component and injects visibility control via props.

/* HOC: withVisibility.js */
import React, { useState, Fragment } from 'react';

const withVisibility = WrappedComponent => props => {
  const [visible, setVisible] = useState(false);
  return (
    <Fragment>
      <button onClick={() => setVisible(true)}>showChild</button>
      {visible && (
        <WrappedComponent
          changeVisible={setVisible}
          visible={visible}
          {...props}
        />
      )}
    </Fragment>
  );
};
export default withVisibility;

/* Child: ShowHookContent.js */
import React, { Component } from 'react';

export default class ShowHookContent extends Component {
  render() {
    const { changeVisible } = this.props;
    return (
      <h1 onClick={() => changeVisible(false)}>Hello Hook!</h1>
    );
  }
}

/* Parent: ShowHook.js */
import React, { Component } from 'react';
import withVisibility from './withVisibility';
import ShowHookContent from './ShowHookContent';

export default withVisibility(ShowHookContent);

The HOC centralises the show/hide logic, making it reusable across multiple Class Components.

3. Ref Forwarding with useImperativeHandle

Ref forwarding lets a parent call methods defined inside a Hook‑based child.

/* Child: SayHello.js */
import React, { useState, useImperativeHandle, forwardRef } from 'react';

function SayHello(props, ref) {
  const [visible, setVisible] = useState(false);
  useImperativeHandle(ref, () => ({ changeVisible: setVisible }));
  return (
    visible && (
      <h1 onClick={() => setVisible(false)}>Hello Hook!</h1>
    )
  );
}
export default forwardRef(SayHello);

/* Parent: ShowHook.js */
import React, { Component } from 'react';
import SayHello from './SayHello';

export default class ShowHook extends Component {
  childRef = null;

  showChild = () => {
    if (this.childRef) {
      this.childRef.changeVisible(true);
    }
  };

  setChildRef = ref => {
    this.childRef = ref;
  };

  render() {
    return (
      <>
        <button onClick={this.showChild}>showChild</button>
        <SayHello ref={this.setChildRef} />
      </>
    );
  }
}

By exposing changeVisible through useImperativeHandle, the Class Component can directly control the Hook child’s visibility.

Limitations

As of React 18, Hooks do not yet implement some Class Component lifecycle methods such as getSnapshotBeforeUpdate, getDerivedStateFromError, and componentDidCatch. These are planned for future releases.

References

How to Use React Hooks in Class Components – https://infinum.com/the-capsized-eight/how-to-use-react-hooks-in-class-components

React Render Props and Use Cases – https://juejin.im/post/6844903624691154952

Hooks FAQ – https://reactjs.org/docs/hooks-faq.html

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

ReacthooksHigher-Order ComponentforwardRefRender PropsClass Component
政采云技术
Written by

政采云技术

ZCY Technology Team (Zero), based in Hangzhou, is a growth-oriented team passionate about technology and craftsmanship. With around 500 members, we are building comprehensive engineering, project management, and talent development systems. We are committed to innovation and creating a cloud service ecosystem for government and enterprise procurement. We look forward to your joining us.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.