Skip to content

Instantly share code, notes, and snippets.

@mimshins
Last active November 10, 2025 11:47
Show Gist options
  • Select an option

  • Save mimshins/d3de87bd9402cdb8cf60c72e1c32b0cd to your computer and use it in GitHub Desktop.

Select an option

Save mimshins/d3de87bd9402cdb8cf60c72e1c32b0cd to your computer and use it in GitHub Desktop.
A HOC that will help with fine-grained reactivity in Context state managers.
import { createContext, memo, useContext } from "react";
export const withContextSelectors = <
TProps extends object,
TContextValue,
TSelectors extends Record<string, (data: TContextValue) => unknown>,
>(
Component: React.ComponentType<
TProps & { [K in keyof TSelectors]: ReturnType<TSelectors[K]> }
>,
Context: React.Context<TContextValue>,
selectors: TSelectors,
): React.ComponentType<
TProps & { [K in keyof TSelectors]: ReturnType<TSelectors[K]> }
> => {
const MemoisedComponent = memo(Component) as React.ComponentType<
TProps & { [K in keyof TSelectors]: ReturnType<TSelectors[K]> }
>;
const WithContextSelector = (
props: TProps & { [K in keyof TSelectors]: ReturnType<TSelectors[K]> },
) => {
const ctx = useContext(Context);
const contextProps = {} as {
[K in keyof TSelectors]: ReturnType<TSelectors[K]>;
};
for (const key in selectors) {
contextProps[key] = selectors[key]!(ctx) as ReturnType<
TSelectors[typeof key]
>;
}
return (
<MemoisedComponent
{...props}
{...contextProps}
/>
);
};
return WithContextSelector;
};
// EXAMPLE:
const W = withContextSelectors(
function MyComp(props: {
name: string;
age: number;
lastName: string;
fullName: string;
}) {
return <></>;
},
createContext<{ firstName: string; lastName: string; age: number }>({
firstName: "",
lastName: "",
age: 0,
}),
{
lastName: ctx => ctx.lastName,
fullName: ctx => `${ctx.firstName} ${ctx.lastName}`,
},
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment