Skip to content

Instantly share code, notes, and snippets.

@chaance
Created September 21, 2024 09:10
Show Gist options
  • Save chaance/a5fa6df5faee5f4b61386b65f5809e3d to your computer and use it in GitHub Desktop.
Save chaance/a5fa6df5faee5f4b61386b65f5809e3d to your computer and use it in GitHub Desktop.
useMap / useSet
import * as React from 'react';
export function useMap<K = unknown, V = unknown>(
initialEntries?: readonly (readonly [K, V])[] | null,
): IMap<K, V> {
const [map, setMap] = React.useState(() => new Map(initialEntries));
return {
raw: map,
clear: React.useCallback(() => {
setMap((map) => {
return map.size === 0 ? map : new Map();
});
}, []),
delete: React.useCallback((key: K) => {
setMap((map) => {
if (!map.has(key)) {
return map;
}
const copy = new Map(map);
copy.delete(key);
return copy;
});
}, []),
get: React.useCallback((key: K) => map.get(key), [map]),
has: React.useCallback((key: K) => map.has(key), [map]),
set: React.useCallback(
(key: K, action: V | ((prevState: V | undefined) => V)) => {
setMap((map) => {
const current = map.get(key);
const next = isFunction(action) ? action(current) : action;
if (current === next) {
return map;
}
return new Map(map.set(key, next));
});
},
[],
),
size: map.size,
map: React.useCallback(
(callbackFn) => {
const result: ReturnType<typeof callbackFn>[] = [];
for (const entry of map) {
result.push(callbackFn(entry, result.length, map));
}
return result;
},
[map],
),
};
}
interface IMap<K, V> {
raw: Map<K, V>;
clear(): void;
delete(key: K): void;
get(key: K): V | undefined;
has(key: K): boolean;
set(key: K, action: V | ((prevState: V | undefined) => V)): void;
map<U>(callbackFn: (entry: [K, V], index: number, map: Map<K, V>) => U): U[];
readonly size: number;
}
function isFunction(value: unknown): value is (...args: any[]) => any {
return typeof value === 'function';
}
import * as React from 'react';
export function useSet<T = unknown>(
initialValues: readonly T[] | null,
): ISet<T> {
const [set, setSet] = React.useState(() => new Set(initialValues));
return {
raw: set,
add: React.useCallback((value: T) => {
setSet((set) => {
if (set.has(value)) {
return set;
}
const copy = new Set(set);
copy.add(value);
return copy;
});
}, []),
clear: React.useCallback(() => {
setSet((set) => {
return set.size === 0 ? set : new Set();
});
}, []),
delete: React.useCallback(
(value: T) =>
setSet((set) => {
if (!set.has(value)) {
return set;
}
const copy = new Set(set);
copy.delete(value);
return copy;
}),
[],
),
has: React.useCallback((value: T) => set.has(value), [set]),
map: React.useCallback(
(callbackFn) => {
const result: ReturnType<typeof callbackFn>[] = [];
for (const value of set) {
result.push(callbackFn(value, result.length, set));
}
return result;
},
[set],
),
size: set.size,
};
}
interface ISet<T> {
raw: Set<T>;
add(value: T): void;
clear(): void;
delete(value: T): void;
has(value: T): boolean;
map<U>(callbackFn: (value: T, index: number, set: Set<T>) => U): U[];
readonly size: number;
}
function isFunction(value: unknown): value is (...args: any[]) => any {
return typeof value === 'function';
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment