@applicaster/zapp-react-native-utils
Version:
Applicaster Zapp React Native utilities package
73 lines (62 loc) • 2.75 kB
text/typescript
import * as React from "react";
import createReactContext from "create-react-context";
import * as R from "ramda";
import { getSetterName, NOOP } from "./helpers";
import { createProvider } from "./provider";
import { createWithConsumerDecorator } from "./withConsumer";
import { createWithProviderDecorator } from "./withProvider";
const reactContextCreator = React.createContext;
// Depending on the version of React used, the `createContext` function may not be available
// if this is the case, we fall back to a polyfill library
const contextCreatorFn =
reactContextCreator && typeof reactContextCreator === "function"
? reactContextCreator
: createReactContext;
/**
* @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
* @property {React.Context} Context.ReactContext React context object
* 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}
*/
export function createContext(initialContext, stateValidator = R.T) {
// first we extract the properties name, and create setters name for those
const contextPropertiesNames = R.keys(initialContext);
const contextSettersNames = R.map(getSetterName, contextPropertiesNames);
// we create a React Context with the properties & their setters, assigning a noop function
// temporarily (will be overriden by proper setters in the provider component)
const ReactContext = R.compose(
contextCreatorFn,
R.merge(initialContext),
R.zipObj(contextSettersNames),
R.map(R.always(NOOP))
)(contextSettersNames);
// we call the module function to fabricate the Provider & Consumer components
const Provider = createProvider({
ReactContext,
initialContext,
contextPropertiesNames,
contextSettersNames,
stateValidator,
});
const { Consumer } = ReactContext;
// and their matching decorators
const withProvider = createWithProviderDecorator(Provider);
const withConsumer = createWithConsumerDecorator(Consumer);
return {
Provider,
Consumer,
withProvider,
withConsumer,
ReactContext,
};
}