diff --git a/docs/useSet.md b/docs/useSet.md
index 8b6f620a..55407202 100644
--- a/docs/useSet.md
+++ b/docs/useSet.md
@@ -8,7 +8,7 @@ React state hook that tracks a [Set](https://developer.mozilla.org/en-US/docs/We
import {useSet} from 'react-use';
const Demo = () => {
- const [set, { add, has, remove, reset }] = useSet(new Set(['hello']));
+ const [set, { add, has, remove, toggle, reset }] = useSet(new Set(['hello']));
return (
@@ -17,6 +17,7 @@ const Demo = () => {
+
{JSON.stringify(Array.from(set), null, 2)}
);
diff --git a/src/useSet.ts b/src/useSet.ts
index 9498413d..4ceca005 100644
--- a/src/useSet.ts
+++ b/src/useSet.ts
@@ -4,6 +4,7 @@ import { useState, useMemo, useCallback } from 'react';
export interface StableActions {
add: (key: K) => void;
remove: (key: K) => void;
+ toggle: (key: K) => void;
reset: () => void;
}
@@ -14,14 +15,18 @@ export interface Actions extends StableActions {
const useSet = (initialSet = new Set()): [Set, Actions] => {
const [set, setSet] = useState(initialSet);
- const stableActions = useMemo>(
- () => ({
- add: item => setSet(prevSet => new Set([...Array.from(prevSet), item])),
- remove: item => setSet(prevSet => new Set(Array.from(prevSet).filter(i => i !== item))),
- reset: () => setSet(initialSet),
- }),
- [setSet]
- );
+ const stableActions = useMemo>(() => {
+ const add = (item: K) => setSet(prevSet => new Set([...Array.from(prevSet), item]));
+ const remove = (item: K) => setSet(prevSet => new Set(Array.from(prevSet).filter(i => i !== item)));
+ const toggle = (item: K) =>
+ setSet(prevSet =>
+ prevSet.has(item)
+ ? new Set(Array.from(prevSet).filter(i => i !== item))
+ : new Set([...Array.from(prevSet), item])
+ );
+
+ return { add, remove, toggle, reset: () => setSet(initialSet) };
+ }, [setSet]);
const utils = {
has: useCallback(item => set.has(item), [set]),
diff --git a/stories/useSet.story.tsx b/stories/useSet.story.tsx
index 9166b2a3..f1b5e050 100644
--- a/stories/useSet.story.tsx
+++ b/stories/useSet.story.tsx
@@ -4,7 +4,7 @@ import { useSet } from '../src';
import ShowDocs from './util/ShowDocs';
const Demo = () => {
- const [set, { add, has, remove, reset }] = useSet(new Set(['hello']));
+ const [set, { add, has, remove, reset, toggle }] = useSet(new Set(['hello']));
return (
@@ -13,6 +13,7 @@ const Demo = () => {
+
{JSON.stringify(Array.from(set), null, 2)}
);
diff --git a/tests/useSet.test.ts b/tests/useSet.test.ts
index 20e734b4..787eb5e4 100644
--- a/tests/useSet.test.ts
+++ b/tests/useSet.test.ts
@@ -12,6 +12,7 @@ it('should init set and utils', () => {
has: expect.any(Function),
add: expect.any(Function),
remove: expect.any(Function),
+ toggle: expect.any(Function),
reset: expect.any(Function),
});
});
@@ -94,6 +95,28 @@ it('should remove existing key', () => {
expect(result.current[0]).toEqual(new Set([1]));
});
+it('should remove an existing key on toggle', () => {
+ const { result } = setUp(new Set([1, 2]));
+ const [, utils] = result.current;
+
+ act(() => {
+ utils.toggle(2);
+ });
+
+ expect(result.current[0]).toEqual(new Set([1]));
+});
+
+it('should add a new key on toggle', () => {
+ const { result } = setUp(new Set([1]));
+ const [, utils] = result.current;
+
+ act(() => {
+ utils.toggle(2);
+ });
+
+ expect(result.current[0]).toEqual(new Set([1, 2]));
+});
+
it('should do nothing if removing non-existing key', () => {
const { result } = setUp(new Set(['a', 'b']));
const [, utils] = result.current;
@@ -125,7 +148,7 @@ it('should reset to initial set provided', () => {
it('should memoized its utils methods', () => {
const { result } = setUp(new Set(['a', 'b']));
const [, utils] = result.current;
- const { add, remove, reset } = utils;
+ const { add, remove, reset, toggle } = utils;
act(() => {
add('foo');
@@ -133,5 +156,6 @@ it('should memoized its utils methods', () => {
expect(result.current[1].add).toBe(add);
expect(result.current[1].remove).toBe(remove);
+ expect(result.current[1].toggle).toBe(toggle);
expect(result.current[1].reset).toBe(reset);
});