@aweebit/react-essentials
v0.10.7
Published
[](https://www.npmjs.com/package/@aweebit/react-essentials)
Downloads
266
Readme
@aweebit/react-essentials
- useEventListener()
- useIsomorphicLayoutEffect()
- useReducerWithDeps()
- useStateWithDeps()
- contextualize()
- createSafeContext()
- wrapJSX()
Requirements
- React ≥ 18
- TypeScript ≥ 5.4
useEventListener
const useEventListener: UseEventListener;Defined in: hooks/useEventListener.ts:136
Adds handler as a listener for the event eventName of target with the
provided options applied
The following call signatures are available:
function useEventListener(eventName, handler, options?): void;
function useEventListener(target, eventName, handler, options?): void;For the full definition of the hook's type, see UseEventListener.
If target is not provided, window is used instead.
If target is null, no event listener is added. This is useful when
working with DOM element refs, or when the event listener needs to be removed
temporarily.
Example
useEventListener('resize', () => {
console.log(window.innerWidth, window.innerHeight);
});
useEventListener(document, 'visibilitychange', () => {
console.log(document.visibilityState);
});
const buttonRef = useRef<HTMLButtonElement>(null);
useEventListener(buttonRef, 'click', () => console.log('click'));See
useIsomorphicLayoutEffect()
const useIsomorphicLayoutEffect: (effect, deps?) => void;Defined in: hooks/useIsomorphicLayoutEffect.ts:12
Identical to useLayoutEffect, except it does not result in
warnings when used on the server
Parameters
effect
EffectCallback
deps?
DependencyList
Returns
void
useReducerWithDeps()
function useReducerWithDeps<S, A>(
reducer,
initialState,
deps,
): [S, ActionDispatch<A>];Defined in: hooks/useReducerWithDeps.ts:64
useReducer hook with an additional dependency array deps that
resets the state to initialState when dependencies change
This hook is the reducer pattern counterpart of useStateWithDeps.
Due to React's limitations, a change in dependencies always causes two renders when using this hook. The result of the first render is thrown away as described in useState > Storing information from previous renders.
For motivation and examples, see https://github.com/facebook/react/issues/33041.
On linter support
The react-hooks/exhaustive-deps ESLint rule doesn't support hooks where
the dependency array parameter is at any other position than the second.
However, as we would like to keep the hook as compatible with useReducer as
possible, we don't want to artificially change the parameter's position.
Therefore, there will be no warnings about missing dependencies.
Because of that, additional caution is advised!
Be sure to check that no dependencies are missing from the deps array.
Related issue: https://github.com/facebook/react/issues/25443.
Unlike eslint-plugin-react-hooks maintained by React's team, the unofficial
useExhaustiveDependencies rule provided for Biome by Biome's team
does actually have support for dependency arrays at other positions, see
useExhaustiveDependencies > Options > Validating dependencies.
Type Parameters
S
A extends AnyActionArg
Parameters
reducer
(prevState, ...args) => S
The reducer function that specifies how the state gets updated
initialState
S | (previousState?) => S
The value to which the state is set when the component is mounted or dependencies change
It can also be a function that returns a state value. If the state is reset
due to a change of dependencies, this function will be passed the previous
state as its argument (will be undefined in the first call upon mount).
deps
DependencyList
Dependencies that reset the state to initialState
Returns
[S, ActionDispatch<A>]
useStateWithDeps()
function useStateWithDeps<S>(
initialState,
deps,
): [S, Dispatch<SetStateAction<S>>];Defined in: hooks/useStateWithDeps.ts:62
useState hook with an additional dependency array deps that
resets the state to initialState when dependencies change
Due to React's limitations, a change in dependencies always causes two renders when using this hook. The result of the first render is thrown away as described in useState > Storing information from previous renders.
For motivation and more examples, see https://github.com/facebook/react/issues/33041.
Example
type Activity = 'breakfast' | 'exercise' | 'swim' | 'board games' | 'dinner';
const timeOfDayOptions = ['morning', 'afternoon', 'evening'] as const;
type TimeOfDay = (typeof timeOfDayOptions)[number];
const activityOptionsByTimeOfDay: {
[K in TimeOfDay]: [Activity, ...Activity[]];
} = {
morning: ['breakfast', 'exercise', 'swim'],
afternoon: ['exercise', 'swim', 'board games'],
evening: ['board games', 'dinner'],
};
function Example() {
const [timeOfDay, setTimeOfDay] = useState<TimeOfDay>('morning');
const activityOptions = activityOptionsByTimeOfDay[timeOfDay];
const [activity, setActivity] = useStateWithDeps<Activity>(
(prev) => {
// Make sure activity is always valid for the current timeOfDay value,
// but also don't reset it unless necessary:
return prev && activityOptions.includes(prev) ? prev : activityOptions[0];
},
[activityOptions],
);
return '...';
}Type Parameters
S
Parameters
initialState
S | (previousState?) => S
The value to which the state is set when the component is mounted or dependencies change
It can also be a function that returns a state value. If the state is reset
due to a change of dependencies, this function will be passed the previous
state as its argument (will be undefined in the first call upon mount).
deps
DependencyList
Dependencies that reset the state to initialState
Returns
[S, Dispatch<SetStateAction<S>>]
contextualize()
function contextualize<Children>(children): ContextualizePipe<Children>;Defined in: misc/contextualize.tsx:78
An alternative way to provide context values to component trees that avoids ever-increasing indentation
A context-specific version of the more general wrapJSX function.
Example
// Before:
return (
<CourseIdContext.Provider value={courseId}>
<DeckIdContext.Provider value={deckId}>
<FlashcardsContext.Provider value={flashcards}>
<EventHandlersContext.Provider value={eventHandlers}>
<Header />
<Main />
<Footer />
</EventHandlersContext.Provider>
</FlashcardsContext.Provider>
</DeckIdContext.Provider>
</CourseIdContext.Provider>
);
// After:
const jsx = (
<>
<Header />
<Main />
<Footer />
</>
);
return contextualize(jsx)
.with(EventHandlersContext, eventHandlers)
.with(FlashcardsContext, flashcards)
.with(DeckIdContext, deckId)
.with(CourseIdContext, courseId)
.end();Type Parameters
Children extends ReactNode
Parameters
children
Children
The children to contextualize
Returns
ContextualizePipe<Children>
An object with the following properties:
with: a function that accepts a contextContextand a valuevaluefor it as arguments and returnscontextualize(<Context.Provider value={value}>{children}</Context.Provider>)end: a function that returnschildren
See
createSafeContext()
function createSafeContext<T>(): <DisplayName>(displayName) => {
[K in `${string}Context`]: Context<T>;
} & {
[K in `use${string}`]: () => T;
};Defined in: misc/createSafeContext.ts:61
For a given type T, returns a function that produces both a context of that
type and a hook that returns the current context value if one was provided,
or throws an error otherwise
The advantages over vanilla createContext are that no default value has to
be provided, and that a meaningful context name is displayed in dev tools
instead of generic Context.Provider.
Example
enum Direction {
Up,
Down,
Left,
Right,
}
// Before:
const DirectionContext = createContext<Direction | undefined>(undefined);
DirectionContext.displayName = 'DirectionContext';
const useDirection = () => {
const direction = useContext(DirectionContext);
if (direction === undefined) {
// Called outside of a <DirectionContext.Provider> boundary!
// Or maybe undefined was explicitly provided as the context value
// (ideally that shouldn't be allowed, but it is because we had to include
// undefined in the context type so as to provide a meaningful default)
throw new Error('No DirectionContext value was provided');
}
// Thanks to the undefined check, the type is now narrowed down to Direction
return direction;
};
// After:
const { DirectionContext, useDirection } =
createSafeContext<Direction>()('Direction'); // That's it :)
const Parent = () => (
// Providing undefined as the value is not allowed 👍
<Direction.Provider value={Direction.Up}>
<Child />
</Direction.Provider>
);
const Child = () => `Current direction: ${Direction[useDirection()]}`;Type Parameters
T
never
Returns
A function that accepts a single string argument displayName (e.g.
"Direction") and returns an object with the following properties:
`${displayName}Context`(e.g.DirectionContext): the context`use${displayName}`(e.g.useDirection): a hook that returns the current context value if one was provided, or throws an error otherwise
<DisplayName>(displayName): { [K in `${string}Context`]: Context<T> } & { [K in `use${string}`]: () => T };Type Parameters
DisplayName extends string
Parameters
displayName
[T] extends [never] ? never : string extends DisplayName ? never : DisplayName
Returns
{ [K in `${string}Context`]: Context<T> } & { [K in `use${string}`]: () => T }
wrapJSX()
function wrapJSX<Children>(children): JSXWrapPipe<Children>;Defined in: misc/wrapJSX.tsx:98
An alternative way to compose JSX that avoids ever-increasing indentation
A more general version of the context-specific contextualize
function.
Example
// Before:
createRoot(document.getElementById('root')!).render(
<StrictMode>
<I18nextProvider i18n={i18n}>
<QueryClientProvider client={queryClient}>
<NuqsAdapter>
<ThemeProvider theme={theme}>
<ToasterProvider>
<App />
</ToasterProvider>
</ThemeProvider>
</NuqsAdapter>
</QueryClientProvider>
</I18nextProvider>
</StrictMode>,
);
// After:
createRoot(document.getElementById('root')!).render(
wrapJSX(<App />)
.with(ToasterProvider)
.with(ThemeProvider, { theme })
.with(NuqsAdapter)
.with(QueryClientProvider, { client: queryClient })
.with(I18nextProvider, { i18n })
.with(StrictMode)
.end(),
);Type Parameters
Children extends ReactNode
Parameters
children
Children
The children to wrap
Returns
JSXWrapPipe<Children>
An object with the following properties:
with: a function that accepts a componentComponentand propspropsfor it as arguments and returnswrapJSX(<Component {...props}>{children}</Component>)end: a function that returnschildren
See
UseEventListener
type UseEventListener = UseEventListenerWithImplicitWindowTarget &
UseEventListenerWithExplicitGlobalTarget &
UseEventListenerWithAnyExplicitTarget;Defined in: hooks/useEventListener.ts:13
The type of useEventListener
See
useEventListener,
UseEventListenerWithImplicitWindowTarget,
UseEventListenerWithExplicitGlobalTarget,
UseEventListenerWithAnyExplicitTarget
UseEventListenerWithImplicitWindowTarget()
type UseEventListenerWithImplicitWindowTarget = <K>(...args) => void;Defined in: hooks/useEventListener.ts:22
Type Parameters
K extends keyof WindowEventMap
Parameters
...args
UseEventListenerWithImplicitWindowTargetArgs<K>
Returns
void
See
useEventListener,
UseEventListenerWithImplicitWindowTargetArgs
UseEventListenerWithExplicitGlobalTarget
type UseEventListenerWithExplicitGlobalTarget =
UseEventListenerWithExplicitTarget<Window, WindowEventMap> &
UseEventListenerWithExplicitTarget<Document, DocumentEventMap> &
UseEventListenerWithExplicitTarget<HTMLElement, HTMLElementEventMap> &
UseEventListenerWithExplicitTarget<SVGElement, SVGElementEventMap> &
UseEventListenerWithExplicitTarget<MathMLElement, MathMLElementEventMap>;Defined in: hooks/useEventListener.ts:33
See
useEventListener,
UseEventListenerWithExplicitTarget
UseEventListenerWithExplicitTarget()
type UseEventListenerWithExplicitTarget<Target, EventMap> = <T, K>(
...args
) => void;Defined in: hooks/useEventListener.ts:45
Type Parameters
Target extends EventTarget
EventMap
Type Parameters
T extends Target
K extends keyof EventMap
Parameters
...args
UseEventListenerWithExplicitTargetArgs<EventMap, T, K>
Returns
void
See
useEventListener,
UseEventListenerWithExplicitTargetArgs
UseEventListenerWithAnyExplicitTarget
type UseEventListenerWithAnyExplicitTarget = UseEventListenerWithExplicitTarget<
EventTarget,
Record<string, Event>
>;Defined in: hooks/useEventListener.ts:57
See
useEventListener,
UseEventListenerWithExplicitTarget
UseEventListenerWithImplicitWindowTargetArgs
type UseEventListenerWithImplicitWindowTargetArgs<K> =
UseEventListenerWithExplicitTargetArgs<WindowEventMap, Window, K> extends [
unknown,
...infer Args,
]
? Args
: never;Defined in: hooks/useEventListener.ts:65
Type Parameters
K extends keyof WindowEventMap
See
useEventListener,
UseEventListenerWithExplicitTargetArgs
UseEventListenerWithExplicitTargetArgs
type UseEventListenerWithExplicitTargetArgs<EventMap, T, K> = [
(
| T
| (RefObject<T> & {
addEventListener?: never;
})
| null
),
K,
(this, event) => void,
AddEventListenerOptions | boolean | undefined,
];Defined in: hooks/useEventListener.ts:79
Type Parameters
EventMap
T extends EventTarget
K extends keyof EventMap
See
ContextualizePipe
type ContextualizePipe<Children> = {
with: ContextualizeWith;
end: () => Children;
};Defined in: misc/contextualize.tsx:12
The return type of contextualize
See
contextualize,
ContextualizeWith
Type Parameters
Children extends ReactNode
Properties
with
end
() => Children
ContextualizeWith()
type ContextualizeWith = <T>(Context, value) => ContextualizePipe<ReactElement>;Defined in: misc/contextualize.tsx:22
Type Parameters
T
Parameters
Context
Context<T>
value
NoInfer<T>
Returns
ContextualizePipe<ReactElement>
See
contextualize,
ContextualizePipe
JSXWrapPipe
type JSXWrapPipe<Children> = {
with: WrapJSXWith<Children>;
end: () => Children;
};Defined in: misc/wrapJSX.tsx:18
The return type of wrapJSX
See
Type Parameters
Children extends ReactNode
Properties
with
WrapJSXWith<Children>
end
() => Children
WrapJSXWith()
type WrapJSXWith<Children> = <C>(...args) => JSXWrapPipe<ReactElement>;Defined in: misc/wrapJSX.tsx:28
Type Parameters
Children extends ReactNode
Type Parameters
C extends keyof JSX.IntrinsicElements | JSXElementConstructor<any>
Parameters
...args
["children" extends keyof ComponentProps<C> ? [Children] extends [ComponentProps<C>["children"]] ? C : never : never, ...(Record<never, unknown> extends Omit<ComponentProps<C>, "children"> ? [props?: JSX.IntrinsicAttributes & Omit<ComponentProps<C>, "children">] : [props: JSX.IntrinsicAttributes & Omit<ComponentProps<C>, "children">])]
Returns
JSXWrapPipe<ReactElement>
