npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

react-context-creator

v1.0.1

Published

Easy React context

Downloads

3

Readme

ReactContext

This module enables to quickly and simply enable access to a React context, using the new React API. If you are using a version of React that doesn't have the createContext function, this module will fallback on a polyfill.

How to Create a context

the module has a single named function export called createContext. You call it with 2 properties :

  • an initial context object with the keys of the properties and their initial values
  • a stateValidator predicate which can be used to validate a context change agains some values. it is invoked with stateValidator({ property, value }) where property is the name of the property that is being modified, and the new value.

The createContext function will automatically create setters functions for all the properties you declare in the initial context. For instance, if your initial context is { foo: "someVal", barBaz: "someOtherVal" }, the function will automatically create setFoo and setBarBaz functions to manipulate these values in the context.

The function returns an object with components & decorators to consume & provide the context. from the jsdoc :

/**
 * @typedef Context
 * @property {Object} Context.Provider react class component to use as context provider
 * @property {Function} Context.Consumer react functional component to use as context consumer
 * @property {Function} Context.withProvider HOC to apply the context provider
 * @property {function} Context.withConsumer HOC to apply the context consumer. passes the context as props
 * to the wrapped component
 */

/**
 * Creates a React Context and returns consumer & providers components & decorators to interact
 * with this context.
 * @param {Object} initialContext map of context properties and their initial values
 * @param {Function} stateValidator optional predicate to tell whether the state update is valid or not
 * @returns {Context} Object containing the context components & decorators {@link Context}
 */

Usage


import { createContext } from "react-context-creator";

const initialContext = { appState: "Loading" };
const stateValidator = ({ property, value }) => property === "appState" && ["laoding", "in_background", "launched"].includes(value);
// stateValidator is optional, but it's convenient to avoid bugs when consumers try to update either an incorrect property or an incorrect value

const AppStateContext = createContext(initialContext, stateValidator);

const MyReactApp = props => (
  <View>
    <AppStateContext.Consumer>
      { ({appState}) => <View><Text>AppState is {appState}</Text><View> }
    </AppStateContext.Consumer>
    /* ... */
    <AppStateContext.Consumer>
      { ({setAppState}) => <Button label="App Finished Loading" onPress={() => setAppState("launched")} />}
    </AppStateContext.Consumer>
  </View>
)

// don't forget the Provider !
const DecoratedApp = AppStateContext.withProvider(MyReactApp);

export default DecoratedApp;

Or with the classic Counter example

import { createContext } from "react-context-creator";

const initialContext = { counter: 0 };
const stateValidator = ({ property, value }) =>
  property === "counter" && typeof value === "number" && !Number.isNaN(value);

const CounterContext = createContext(initialContext, stateValidator);

// Using the decorator or the component with a render function is almost equivalent
// Just beware of props override if using the decorator. If you have a prop with a name that is also in the context,
// the value from the context will override the prop
const Header = CounterContext.withConsumer(({ counter }) => (
  <View>
    <Text>Counter: {counter}</Text>
  </View>
));

const CounterApp = () => {
  <View>
    <Header />
    <CounterContext.Consumer>
      {({ counter, setCounter }) => (
        <View>
          <Button label="increment" onPress={() => setCounter(counter + 1)} />
          <Button label="decrement" onPress={() => setCounter(counter - 1)} />
          <Button label="reset" onPress={() => setCounter(0)} />
        </View>
      )}
    </CounterContext.Consumer>
  </View>;
};

// We could also have wrapped `CounterApp` with <CounterContext.Provider>
export const DecoratedCounterApp = CounterContext.withProvider(CounterApp);

This pattern is very powerful as the different consumers (whether to get the value or to set it) can be in completely different locations in the code base. This avoids having to resort to Redux and it's consequent boilerplate code to easily pass values & their setters up & down the tree in a react app. It also helps to keep things in isolation properly

How to provide the context

the module offers 2 ways of providing the context

  1. with a component
import { AppStateContext } from "../AppStateContext";

const MyComponent = props => (
  <AppStateContext.Provider>
    <View>/* anything... */</View>
  </AppStateContext.Provider>
);

export default MyComponent;
  1. with a decorator
import { AppStateContext } from "../AppStateContext";

const MyComponent = AppStateContext.withProvider(props => (
  <View>/* anything... */</View>
));

export default MyComponent;

How to consume a context

Similarly, leveraging the context can be done in 2 ways :

  1. with the consumer component
import { AppStateContext } from "../AppStateContext";

export function MyComponentWithContext(props) {
  return (
    <View>
      <Text> Header </Text>
      <AppStateContext.Consumer>
        {({ appState, setAppState }) => {
          return (
            <View>
              <Text>App is in {appState}</Text>
              <View>
                <Button
                  label="set app to launched"
                  onPress={() => setAppState("launched")}
                />
              </View>
            </View>
          );
        }}
      </AppStateContext.Consumer>
    </View>
  );
}
  1. with the decorator
import { AppStateContext } from "../AppStateContext";

function MyComponent({ appState, setAppState, ...otherProps }) {
  return (
    <View>
      <Text> Header </Text>
      <View>
        <Text>App is in {appState}</Text>
        <View>
          <Button
            label="set app to launched"
            onPress={() => setAppState("launched")}
          />
        </View>
      </View>
    </View>
  );
}

export const MyDecoratedComponent = withDisplayStateConsumer(MyComponent);