DEV Community

Cover image for Automate React.Context creation
Alexey Lysenko
Alexey Lysenko

Posted on

Automate React.Context creation

When the React team implemented Context API, developers started to have a better way to pass data through the components. I love to use many local contexts to wrap some parts of the app and have shared data without props chaos.

This is how we can automate React.Context creation, by passing in it our custom hook function:

import * as React from 'react';

type Hook<T, P> = (props: P) => T;

type ContextHook<T> = () => T;
type Provider<P> = React.FunctionComponent<P>;
type CreateContextHookReturn<T, P> = [Provider<P>, ContextHook<T>];

export function createContextHook<T = unknown, P = unknown>(
  useHook: Hook<T, P>,
  args: { name: string }
): CreateContextHookReturn<T, P> {
  const Context = React.createContext<T | undefined>(undefined);

  function useContextHook(): T {
    const context = React.useContext(Context);

    if (context === undefined) {
      throw new Error(
        `${args.name} Context value is undefined. Make sure you use the ${args.name} Provider before using the context.`
      );
    }

    return context!;
  }

  function Provider(props: React.PropsWithChildren<P>) {
    const value = useHook(props);
    return <Context.Provider value={value}>{props.children}</Context.Provider>;
  }

  return [Provider, useContextHook];
}
Enter fullscreen mode Exit fullscreen mode

Then create your hook and pass it to the createContextHook:

import React from 'react';
import { createContextHook } from '../createContextHook';

// 1. Create your custom hook
type UseMyCustomHookProps = {
  someInitialValue: number;
}

function useMyCustomeHook(props: UseMyCustomeHookProps) {
  const [count, setCount] = React.useState(props.someInitialValue);
  return { count, setCount };
}

// 2. Create and get the Context Hook and Provider
Wrapped your application tree to the provider.

const [MyCustomHookProvider, useMyCustomHookContext] = createContextHook<
  // the return value of the hook
  ReturnType<typeof useMyHook>,
  // the hook input parameter
  UseMyHookProps
>(
  // Pass your hook reference
  useMyCustomHook,
  {
    // `name` is used only for debugging propose when you failed to connect the hook
    name: "MyCustomeHook"
  }
);

export { MyHookProvider, useMyHookContext };
Enter fullscreen mode Exit fullscreen mode

Or use npm package:

import { createContextHook } from '@straw-hat/react-hooks';
Enter fullscreen mode Exit fullscreen mode

Latest comments (1)

Collapse
 
jfullerco profile image
jfullerco

Big fan of dynamic/flexible object creation! Will have to dig in to this more but great concept!! 👍