vardius
vardius

Reputation: 6546

Multiple nested consumers for React 16.3.0 Context API

Following the new context API for react 16.3.0 I've created HOC so that my context is easier consumed by many components.

But if I have more then one component that consumes context nested one after another, react throws error.

Lets say for my example i have css module i want to pass down and HOC looks as follow:

import React from 'react';
import CssModuleContext from './CssModuleContext';

export default function withCssModule(Component) {
  return function CssModuleComponent(props) {
    return (
      <CssModuleContext.Consumer>
        {cx => <Component {...props} cssModule={cx} />}
      </CssModuleContext.Consumer>
    );
  };
}

Then I have two components that consumes this context:

@withCssModule
export default class A extends PureComponent {
  static B = B;

  static propTypes = {
    cssModule: PropTypes.func,
  };

  render() { ... }
}

@withCssModule
export default class B extends PureComponent {
  static propTypes = {
    cssModule: PropTypes.func,
  };

  render() { ... }
}

And the usage looks as follow:

render() {
  return(
    <A>
      <A.B />
    </A>
  );
}

React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.

which throws an error, when I use only one of those components there is no error, but i can not nest them. Is this a common error? Is there a fix for it ? Or maybe am I doing something wrong ?

CssModuleContext.js

import React from 'react';

const defaultCssModule = null; // we want to use component defined module by default

const CssModuleContext = React.createContext(defaultCssModule);

export default CssModuleContext;

CssModuleProvider.js

import React from 'react';
import PropTypes from 'prop-types';
import CssModuleContext from './CssModuleContext';

export default class CssModuleProvider extends React.Component {
  static propTypes = {
    children: PropTypes.element.isRequired,
    cssModule: PropTypes.func.isRequired,
  }

  constructor(props) {
    super(props);

    const { cssModule } = this.props;

    this.state = { cssModule };
  }

  render() {
    return (
      <CssModuleContext.Provider value={this.state.cssModule}>
        {React.Children.only(this.props.children)}
      </CssModuleContext.Provider>
    );
  }
}

Upvotes: 3

Views: 2290

Answers (1)

vardius
vardius

Reputation: 6546

The problem was because i was exporting HOC the static variables where not accessible on that object.

doing the following

@withCssModule
export default class A extends PureComponent {
  static B = B;

  static propTypes = {
    cssModule: PropTypes.func,
  };

  render() { ... }
}

and then trying access the B like that <A.B /> will not work because we export the wrapper not the class itself.

Upvotes: 2

Related Questions