Skip to content

perTarget

ts
perTarget<Target extends WeakKey, Args extends unknown[], T, R = void>(
  create: (target: Target, ...args: Args) => Service<T, R>,
  keyOf?: (...args: Args) => string,
): (target: Target, ...args: Args) => Service<T, R>

Gives a service factory the one instance per target and per options caching every built-in service has.

Usage

ts
import { 
createService
,
perTarget
} from '@studiometa/js-toolkit';
interface FocusProps { readonly
hasFocus
: boolean;
} const
useFocus
=
perTarget
((
target
: Element) =>
createService
<FocusProps>({
props
: () => ({
hasFocus
:
target
.
contains
(
document
.
activeElement
) }),
start
(
emit
) {
const
publish
= () =>
emit
({
hasFocus
:
target
.
contains
(
document
.
activeElement
) });
document
.
addEventListener
('focusin',
publish
);
document
.
addEventListener
('focusout',
publish
);
return () => {
document
.
removeEventListener
('focusin',
publish
);
document
.
removeEventListener
('focusout',
publish
);
}; }, }), ); // The same service, twice.
useFocus
(
document
.
body
);
useFocus
(
document
.
body
);

The key is read by meaning, not by spelling

perTarget() sorts object keys at every depth and drops the keys holding undefined. Arrays keep their order.

js
// One service.
useInView(el, { threshold: 0.5, rootMargin: '0px' });
useInView(el, { rootMargin: '0px', threshold: 0.5 });
useInView(el, { threshold: 0.5, rootMargin: '0px', root: undefined });

That is deliberate: two callers who mean the same thing should share a source, and an options object written in a different order means the same thing.

When you need a keyOf

Only what the platform owns:

  • useInView() gives an object root a stable weak identity, because an element cannot be serialized into a key.
  • useMutation() keeps a canonical init, because the DOM's own rules about which fields imply which are not a plain sort.

Everything else is covered by the default.

The target is a WeakKey

The cache is a WeakMap, so a target that is collected takes its entry with it. Nothing has to be cleaned up, and nothing groups observers across targets.

MIT Licensed