Skip to content

Instantly share code, notes, and snippets.

@circAssimilate
Created August 12, 2021 23:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save circAssimilate/0b7b90ee62f224e20384c6d0e3f88509 to your computer and use it in GitHub Desktop.
Save circAssimilate/0b7b90ee62f224e20384c6d0e3f88509 to your computer and use it in GitHub Desktop.
Context Utils With Use Selectors
/* eslint-disable @typescript-eslint/no-explicit-any */
import {
Context,
createContext,
useContextSelector,
} from '@fluentui/react-context-selector';
type CreateNamedContextReturn<T> = [
Provider: React.Provider<T>,
useContext: <V = T>() => V,
useContextSelector: <S extends (context: T) => any>(
selector: S
) => ReturnType<S>,
useContextSelector: <S extends keyof T>(keys: Array<keyof T>) => Pick<T, S>
];
/**
* Function that creates a react context, hook and selector and
* will trigger re-render if only the selected value (via selector)
* is referentially changed.
*
* @example
* const [PathProvider, usePath, usePathSelector] = createNamedContext()
*
* // 1 - Use the provider
* <PathProvider value={path}>
* {children}
* </PathProvider>
*
* // 2 - Read specific parts of the path for render performance
* const highlightId = usePathSelector(path => path.highlightId)
*
* @see Docs https://www.npmjs.com/package/@fluentui/react-context-selector
*/
export function createNamedContext<T>(
name: string
): CreateNamedContextReturn<T> {
const context = createContext<T | undefined>(undefined) as Context<T>;
context.displayName = name;
const useNamedContext = <V = T>() =>
(useContextSelector(context, (ctx) => ctx) as unknown) as V;
const useSelector = <S extends (context: T) => any>(
selector: S
): ReturnType<S> =>
useContextSelector((context as unknown) as Context<T>, selector);
const useSelectors = <S extends keyof T>(
keys: Array<keyof T>
): Pick<T, S> => {
return keys.reduce<Pick<T, S>>(
(acc, key) => ({
...acc,
[key]: useSelector((s) => s[key]),
}),
{} as any
);
};
return [context.Provider, useNamedContext, useSelector, useSelectors];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment