Skip to content

Instantly share code, notes, and snippets.

@chaance
Created September 21, 2024 09:10
Show Gist options
  • Select an option

  • Save chaance/a5fa6df5faee5f4b61386b65f5809e3d to your computer and use it in GitHub Desktop.

Select an option

Save chaance/a5fa6df5faee5f4b61386b65f5809e3d to your computer and use it in GitHub Desktop.

Revisions

  1. chaance created this gist Sep 21, 2024.
    67 changes: 67 additions & 0 deletions use-map.ts
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,67 @@
    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';
    }
    63 changes: 63 additions & 0 deletions use-set.ts
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,63 @@
    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';
    }