valotas / preact-context

React new Context API for preact
Other
151 stars 8 forks source link

Make warning optional: Consumer used without a Provider #24

Open Download opened 5 years ago

Download commented 5 years ago

I am getting this warning in the console:

Consumer used without a Provider

The message is clear enough, but in my case this is not an issue and I would like to suppress this warning.

I'll describe my use case below and show some example code, but the gist of it is: in my case, the use of context is optional and it is expected that it might not be provided. So I would like the option to suppress the warning.

Would you accept a PR? EDIT: Too late, I already created one :) #25

Background

I am using preact-context to create a theming solution based on CSS modules. The way it works is that the components will by default render the default class names, but you can load the CSS via CSS Modules and pass the module def to a Provider and the components will pick it up and use the modified class names.

The way I did this was to have a default definition in each component that contains the unmodified class names just like they appear in my CSS.

E.g:

const defaultClasses = { 'test': 'test' }

After loading the CSS through CSS Modules, this will produce a module definition with mangled class names (to provide scoping), that looks like this:

const classes = import('./some/styles.css');
// classes == { 'test': 'test_23rfT4' }

The user of my library can wrap the components in a theme Provider and provide the mangled names so the components will use those names i.s.o the default ones.

The components all use a Consumer defined in a common file and when the user needs a Provider, he gets it from this same file:

theme.jsx

import { h } from 'preact'
import { createContext } from 'preact-context'

export const Theme = createContext({})
export const Provider = Theme.Provider
export const Consumer = Theme.Consumer

export default { Theme, Provider, Consumer }

The components use the Consumer to try to get the property classes from the context, defaulting it to an empty object. They then merge the classes over the defaultClasses and use the resulting definition:

card.jsx

import { h } from 'preact'
import defaultClasses from 'solids/card/classes'
import { createHelper } from '../style-classes'
import { Consumer } from '../theme'

export const Card = (props = {}) => {
  const {
    // show an outlined card
    outlined = false,
    children,
    // other attributes
    ...attributes
  } = props

  return (
    <Consumer>{({ classes = {}, scope = 'local' }) => {

      classes = { ...defaultClasses, ...classes }
      let classNames = createHelper(classes, scope)
      attributes.className = classNames(classes.card, {
      [attributes.className || attributes.class]: attributes.className || attributes.class,
        [classes.outlined]: outlined,
      })

      return (
        <div {...attributes}>
          {children}
        </div>
      );
    }}</Consumer>
  )
}

export default Card;

This all works like a charm, except that I get this annoying warning, even in the production build.

Download commented 5 years ago

It might be helpful to look at some actual projects, but I can understand if it's too much :)

valotas commented 5 years ago

Thanks for the PR. I'll try to merge it as soon as possible

Download commented 5 years ago

I created a new PR. I processed your feedback and implemented the log option as well.