Frontend Development 9 min read

How to Use React Context API to Build Flexible, Reusable Components

This tutorial demonstrates how to replace fragile prop‑drilling in a multi‑step React component by leveraging the React Context API, showing step‑by‑step creation of a context, provider, and consumer, refactoring the Stepper component for greater flexibility and reusability across the UI.

Tencent IMWeb Frontend Team
Tencent IMWeb Frontend Team
Tencent IMWeb Frontend Team
How to Use React Context API to Build Flexible, Reusable Components

Original article: https://itnext.io/using-advanced-design-patterns-to-create-flexible-and-reusable-react-components-part-2-react-3c5662b997ab

In the previous part we used compound components and static class methods to create flexible, reusable components, passing

stage

and

handleClick

via props. This approach broke when

props

could only be passed to direct children, making the API rigid.

The solution is to use the React Context API, which allows data sharing across the component tree without explicit prop‑drilling.

React Context API

React provides

createContext

to generate a context object with a

Provider

and a

Consumer

. The provider supplies a value that any descendant can consume.

<code>export const StepperContext = React.createContext();</code>

We create a provider component that holds the shared state (

stage

) and a method (

handleClick

) to update it.

<code>class StepperProvider extends Component {
  state = { stage: 1 };
  render() {
    return (
      <StepperContext.Provider value={{
        stage: this.state.stage,
        handleClick: () => this.setState({ stage: this.state.stage + 1 })
      }}>
        {this.props.children}
      </StepperContext.Provider>
    );
  }
}</code>

Wrap the original

Stepper

component with

StepperProvider

so that all nested components can access the context.

<code>class App extends Component {
  render() {
    return (
      <StepperProvider>
        <Stepper stage={1}>
          <Stepper.Progress>
            <Stepper.Stage num={1} />
          </Stepper.Progress>
          <Stepper.Steps>
            <Stepper.Step num={1} text="Stage 1" />
          </Stepper.Steps>
        </Stepper>
      </StepperProvider>
    );
  }
}</code>

After introducing the context, the original

Stepper

no longer needs its own state or prop‑drilling logic. It can be simplified to expose only static sub‑components.

<code>class Stepper extends Component {
  static Progress = Progress;
  static Steps = Steps;
  static Stage = Stage;
  static Step = Step;
  render() {
    return <div>{this.props.children}</div>;
  }
}
export default Stepper;</code>

Individual sub‑components, such as

Stepper.Step

, consume the context using the

Consumer

component.

<code>export const Step = ({ num, text }) => (
  <StepperContext.Consumer>
    {value => {
      const { stage } = value;
      return stage === num ? <div key={num} style={styles.stageContent}>{text}</div> : null;
    }}
  </StepperContext.Consumer>
);</code>

This pattern, often called “render props”, lets components subscribe to context values without being direct children of the provider.

By refactoring with Context, the component hierarchy becomes more flexible: any component can access

stage

and

handleClick

without strict parent‑child relationships, enabling the addition of new UI elements such as headers.

Images illustrating the component structure and context flow:

The next part of the series will explore using render props to achieve the same flexibility without relying on Context for state sharing.

design patternsfrontendreactContext APIComponent Reusability
Tencent IMWeb Frontend Team
Written by

Tencent IMWeb Frontend Team

IMWeb Frontend Community gathering frontend development enthusiasts. Follow us for refined live courses by top experts, cutting‑edge technical posts, and to sharpen your frontend skills.

0 followers
Reader feedback

How this landed with the community

login 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.